GNUnet  0.10.x
plugin_namestore_postgres.c
Go to the documentation of this file.
1 /*
2  * This file is part of GNUnet
3  * Copyright (C) 2009-2013, 2016-2018 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  */
20 
26 #include "platform.h"
29 #include "gnunet_gnsrecord_lib.h"
30 #include "gnunet_pq_lib.h"
31 #include "namestore.h"
32 
33 
34 #define LOG(kind, ...) GNUNET_log_from(kind, "namestore-postgres", __VA_ARGS__)
35 
36 
40 struct Plugin {
44  const struct GNUNET_CONFIGURATION_Handle *cfg;
45 
49  PGconn *dbh;
50 };
51 
52 
61 static int
63 {
64  struct GNUNET_PQ_ExecuteStatement es_temporary =
65  GNUNET_PQ_make_execute("CREATE TEMPORARY TABLE IF NOT EXISTS ns098records ("
66  " seq BIGSERIAL PRIMARY KEY,"
67  " zone_private_key BYTEA NOT NULL DEFAULT '',"
68  " pkey BYTEA DEFAULT '',"
69  " rvalue BYTEA NOT NULL DEFAULT '',"
70  " record_count INTEGER NOT NULL DEFAULT 0,"
71  " record_data BYTEA NOT NULL DEFAULT '',"
72  " label TEXT NOT NULL DEFAULT '',"
73  " CONSTRAINT zl UNIQUE (zone_private_key,label)"
74  ")"
75  "WITH OIDS");
76  struct GNUNET_PQ_ExecuteStatement es_default =
77  GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS ns098records ("
78  " seq BIGSERIAL PRIMARY KEY,"
79  " zone_private_key BYTEA NOT NULL DEFAULT '',"
80  " pkey BYTEA DEFAULT '',"
81  " rvalue BYTEA NOT NULL DEFAULT '',"
82  " record_count INTEGER NOT NULL DEFAULT 0,"
83  " record_data BYTEA NOT NULL DEFAULT '',"
84  " label TEXT NOT NULL DEFAULT '',"
85  " CONSTRAINT zl UNIQUE (zone_private_key,label)"
86  ")"
87  "WITH OIDS");
88  const struct GNUNET_PQ_ExecuteStatement *cr;
89 
90  plugin->dbh = GNUNET_PQ_connect_with_cfg(plugin->cfg,
91  "namestore-postgres");
92  if (NULL == plugin->dbh)
93  return GNUNET_SYSERR;
94  if (GNUNET_YES ==
96  "namestore-postgres",
97  "ASYNC_COMMIT"))
98  {
99  struct GNUNET_PQ_ExecuteStatement es[] = {
100  GNUNET_PQ_make_try_execute("SET synchronous_commit TO off"),
102  };
103 
104  if (GNUNET_OK !=
106  es))
107  {
108  PQfinish(plugin->dbh);
109  plugin->dbh = NULL;
110  return GNUNET_SYSERR;
111  }
112  }
113  if (GNUNET_YES ==
115  "namestore-postgres",
116  "TEMPORARY_TABLE"))
117  {
118  cr = &es_temporary;
119  }
120  else
121  {
122  cr = &es_default;
123  }
124 
125  {
126  struct GNUNET_PQ_ExecuteStatement es[] = {
127  *cr,
128  GNUNET_PQ_make_try_execute("CREATE INDEX IF NOT EXISTS ir_pkey_reverse "
129  "ON ns098records (zone_private_key,pkey)"),
130  GNUNET_PQ_make_try_execute("CREATE INDEX IF NOT EXISTS ir_pkey_iter "
131  "ON ns098records (zone_private_key,seq)"),
132  GNUNET_PQ_make_try_execute("CREATE INDEX IF NOT EXISTS ir_label "
133  "ON ns098records (label)"),
134  GNUNET_PQ_make_try_execute("CREATE INDEX IF NOT EXISTS zone_label "
135  "ON ns098records (zone_private_key,label)"),
137  };
138 
139  if (GNUNET_OK !=
141  es))
142  {
143  PQfinish(plugin->dbh);
144  plugin->dbh = NULL;
145  return GNUNET_SYSERR;
146  }
147  }
148 
149  {
150  struct GNUNET_PQ_PreparedStatement ps[] = {
151  GNUNET_PQ_make_prepare("store_records",
152  "INSERT INTO ns098records"
153  " (zone_private_key, pkey, rvalue, record_count, record_data, label)"
154  " VALUES ($1, $2, $3, $4, $5, $6)"
155  " ON CONFLICT ON CONSTRAINT zl"
156  " DO UPDATE"
157  " SET pkey=$2,rvalue=$3,record_count=$4,record_data=$5"
158  " WHERE ns098records.zone_private_key = $1"
159  " AND ns098records.label = $6",
160  6),
161  GNUNET_PQ_make_prepare("delete_records",
162  "DELETE FROM ns098records "
163  "WHERE zone_private_key=$1 AND label=$2",
164  2),
165  GNUNET_PQ_make_prepare("zone_to_name",
166  "SELECT seq,record_count,record_data,label FROM ns098records"
167  " WHERE zone_private_key=$1 AND pkey=$2",
168  2),
169  GNUNET_PQ_make_prepare("iterate_zone",
170  "SELECT seq,record_count,record_data,label FROM ns098records "
171  "WHERE zone_private_key=$1 AND seq > $2 ORDER BY seq ASC LIMIT $3",
172  3),
173  GNUNET_PQ_make_prepare("iterate_all_zones",
174  "SELECT seq,record_count,record_data,label,zone_private_key"
175  " FROM ns098records WHERE seq > $1 ORDER BY seq ASC LIMIT $2",
176  2),
177  GNUNET_PQ_make_prepare("lookup_label",
178  "SELECT seq,record_count,record_data,label "
179  "FROM ns098records WHERE zone_private_key=$1 AND label=$2",
180  2),
182  };
183 
184  if (GNUNET_OK !=
186  ps))
187  {
188  PQfinish(plugin->dbh);
189  plugin->dbh = NULL;
190  return GNUNET_SYSERR;
191  }
192  }
193 
194  return GNUNET_OK;
195 }
196 
197 
209 static int
211  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
212  const char *label,
213  unsigned int rd_count,
214  const struct GNUNET_GNSRECORD_Data *rd)
215 {
216  struct Plugin *plugin = cls;
217  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
218  uint64_t rvalue;
219  uint32_t rd_count32 = (uint32_t)rd_count;
220  ssize_t data_size;
221 
222  memset(&pkey,
223  0,
224  sizeof(pkey));
225  for (unsigned int i = 0; i < rd_count; i++)
226  if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type)
227  {
228  GNUNET_break(sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) == rd[i].data_size);
229  GNUNET_memcpy(&pkey,
230  rd[i].data,
231  rd[i].data_size);
232  break;
233  }
235  UINT64_MAX);
236  data_size = GNUNET_GNSRECORD_records_get_size(rd_count,
237  rd);
238  if (data_size < 0)
239  {
240  GNUNET_break(0);
241  return GNUNET_SYSERR;
242  }
243  if (data_size >= UINT16_MAX)
244  {
245  GNUNET_break(0);
246  return GNUNET_SYSERR;
247  }
248  /* if record set is empty, delete existing records */
249  if (0 == rd_count)
250  {
251  struct GNUNET_PQ_QueryParam params[] = {
255  };
257 
259  "delete_records",
260  params);
263  {
264  GNUNET_break(0);
265  return GNUNET_SYSERR;
266  }
268  "postgres",
269  "Record deleted\n");
270  return GNUNET_OK;
271  }
272  /* otherwise, UPSERT (i.e. UPDATE if exists, otherwise INSERT) */
273  {
274  char data[data_size];
275  struct GNUNET_PQ_QueryParam params[] = {
279  GNUNET_PQ_query_param_uint32(&rd_count32),
280  GNUNET_PQ_query_param_fixed_size(data, data_size),
283  };
285  ssize_t ret;
286 
287  ret = GNUNET_GNSRECORD_records_serialize(rd_count,
288  rd,
289  data_size,
290  data);
291  if ((ret < 0) ||
292  (data_size != ret))
293  {
294  GNUNET_break(0);
295  return GNUNET_SYSERR;
296  }
297 
299  "store_records",
300  params);
302  return GNUNET_SYSERR;
303  }
304  return GNUNET_OK;
305 }
306 
307 
316 
320  void *iter_cls;
321 
326 
331  uint64_t limit;
332 };
333 
334 
343 static void
345  PGresult *res,
346  unsigned int num_results)
347 {
348  struct ParserContext *pc = cls;
349 
350  if (NULL == pc->iter)
351  return; /* no need to do more work */
352  for (unsigned int i = 0; i < num_results; i++)
353  {
354  uint64_t serial;
355  void *data;
356  size_t data_size;
357  uint32_t record_count;
358  char *label;
360  struct GNUNET_PQ_ResultSpec rs_with_zone[] = {
361  GNUNET_PQ_result_spec_uint64("seq", &serial),
362  GNUNET_PQ_result_spec_uint32("record_count", &record_count),
363  GNUNET_PQ_result_spec_variable_size("record_data", &data, &data_size),
364  GNUNET_PQ_result_spec_string("label", &label),
365  GNUNET_PQ_result_spec_auto_from_type("zone_private_key", &zk),
367  };
368  struct GNUNET_PQ_ResultSpec rs_without_zone[] = {
369  GNUNET_PQ_result_spec_uint64("seq", &serial),
370  GNUNET_PQ_result_spec_uint32("record_count", &record_count),
371  GNUNET_PQ_result_spec_variable_size("record_data", &data, &data_size),
372  GNUNET_PQ_result_spec_string("label", &label),
374  };
375  struct GNUNET_PQ_ResultSpec *rs;
376 
377  rs = (NULL == pc->zone_key) ? rs_with_zone : rs_without_zone;
378  if (GNUNET_YES !=
380  rs,
381  i))
382  {
383  GNUNET_break(0);
384  return;
385  }
386 
387  if (record_count > 64 * 1024)
388  {
389  /* sanity check, don't stack allocate far too much just
390  because database might contain a large value here */
391  GNUNET_break(0);
393  return;
394  }
395 
396  {
397  struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL(record_count)];
398 
399  GNUNET_assert(0 != serial);
400  if (GNUNET_OK !=
402  data,
403  record_count,
404  rd))
405  {
406  GNUNET_break(0);
408  return;
409  }
410  pc->iter(pc->iter_cls,
411  serial,
412  (NULL == pc->zone_key) ? &zk : pc->zone_key,
413  label,
414  record_count,
415  rd);
416  }
418  }
419  pc->limit -= num_results;
420 }
421 
422 
433 static int
435  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
436  const char *label,
438  void *iter_cls)
439 {
440  struct Plugin *plugin = cls;
441  struct GNUNET_PQ_QueryParam params[] = {
445  };
446  struct ParserContext pc;
448 
449  if (NULL == zone)
450  {
451  GNUNET_break(0);
452  return GNUNET_SYSERR;
453  }
454  pc.iter = iter;
455  pc.iter_cls = iter_cls;
456  pc.zone_key = zone;
458  "lookup_label",
459  params,
461  &pc);
462  if (res < 0)
463  return GNUNET_SYSERR;
465  return GNUNET_NO;
466  return GNUNET_OK;
467 }
468 
469 
482 static int
484  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
485  uint64_t serial,
486  uint64_t limit,
488  void *iter_cls)
489 {
490  struct Plugin *plugin = cls;
492  struct ParserContext pc;
493 
494  pc.iter = iter;
495  pc.iter_cls = iter_cls;
496  pc.zone_key = zone;
497  pc.limit = limit;
498  if (NULL == zone)
499  {
500  struct GNUNET_PQ_QueryParam params_without_zone[] = {
504  };
505 
507  "iterate_all_zones",
508  params_without_zone,
510  &pc);
511  }
512  else
513  {
514  struct GNUNET_PQ_QueryParam params_with_zone[] = {
519  };
520 
522  "iterate_zone",
523  params_with_zone,
525  &pc);
526  }
527  if (res < 0)
528  return GNUNET_SYSERR;
529 
531  (pc.limit > 0))
532  return GNUNET_NO;
533  return GNUNET_OK;
534 }
535 
536 
548 static int
550  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
551  const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
553 {
554  struct Plugin *plugin = cls;
555  struct GNUNET_PQ_QueryParam params[] = {
559  };
561  struct ParserContext pc;
562 
563  pc.iter = iter;
564  pc.iter_cls = iter_cls;
565  pc.zone_key = zone;
567  "zone_to_name",
568  params,
570  &pc);
571  if (res < 0)
572  return GNUNET_SYSERR;
573  return GNUNET_OK;
574 }
575 
576 
583 static void
585 {
586  PQfinish(plugin->dbh);
587  plugin->dbh = NULL;
588 }
589 
590 
597 void *
599 {
600  static struct Plugin plugin;
601  const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
603 
604  if (NULL != plugin.cfg)
605  return NULL; /* can only initialize once! */
606  memset(&plugin, 0, sizeof(struct Plugin));
607  plugin.cfg = cfg;
608  if (GNUNET_OK != database_setup(&plugin))
609  {
610  database_shutdown(&plugin);
611  return NULL;
612  }
614  api->cls = &plugin;
620  "Postgres namestore plugin running\n");
621  return api;
622 }
623 
624 
631 void *
633 {
635  struct Plugin *plugin = api->cls;
636 
637  database_shutdown(plugin);
638  plugin->cfg = NULL;
639  GNUNET_free(api);
641  "Postgres namestore plugin is finished\n");
642  return NULL;
643 }
644 
645 /* end of plugin_namestore_postgres.c */
GNUNET_NETWORK_STRUCT_END ssize_t GNUNET_GNSRECORD_records_get_size(unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd)
Calculate how many bytes we will need to serialize the given records.
struct GNUNET_PQ_ExecuteStatement GNUNET_PQ_make_execute(const char *sql)
Create a struct GNUNET_PQ_ExecuteStatement where errors are fatal.
Definition: pq_exec.c:37
uint64_t GNUNET_CRYPTO_random_u64(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Random on unsigned 64-bit values.
ssize_t GNUNET_GNSRECORD_records_serialize(unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd, size_t dest_size, char *dest)
Serialize the given records to the given destination buffer.
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_string(const char *ptr)
Generate query parameter for a string.
int(* zone_to_name)(void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
Look for an existing PKEY delegation record for a given public key.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
Information needed to run a list of SQL statements using GNUNET_PQ_exec_statements().
Information needed to prepare a list of SQL statements using GNUNET_PQ_prepare_statements().
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Description of a DB result cell.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
static void database_shutdown(struct Plugin *plugin)
Shutdown database connection and associate data structures.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Private ECC key encoded for transmission.
void(* GNUNET_NAMESTORE_RecordIterator)(void *cls, uint64_t serial, const struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key, const char *label, unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd)
Function called for each matching record.
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_GNSRECORD_records_deserialize(size_t len, const char *src, unsigned int rd_count, struct GNUNET_GNSRECORD_Data *dest)
Deserialize the given records to the given destination.
#define LOG(kind,...)
static int ret
Final status code.
Definition: gnunet-arm.c:89
uint64_t limit
Number of results still to return (counted down by number of results given to iterator).
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:46
common internal definitions for namestore service
static char * zone
Name of the zone we manage.
void * cls
Closure to pass to all plugin functions.
static uint64_t record_count
Record count.
static struct GNUNET_ATS_SolverFunctions * plugin
Our solver.
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_string(const char *name, char **dst)
0-terminated string expected.
#define GNUNET_PQ_result_spec_end
End of result parameter specification.
static int namestore_postgres_store_records(void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, const char *label, unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd)
Store a record in the datastore.
#define GNUNET_PQ_query_param_end
End of query parameter specification.
Definition: gnunet_pq_lib.h:94
static int namestore_postgres_zone_to_name(void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
Look for an existing PKEY delegation record for a given public key.
int GNUNET_PQ_prepare_statements(PGconn *connection, const struct GNUNET_PQ_PreparedStatement *ps)
Request creation of prepared statements ps from Postgres.
Definition: pq_prepare.c:63
void * libgnunet_plugin_namestore_postgres_init(void *cls)
Entry point for the plugin.
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_variable_size(const char *name, void **dst, size_t *sptr)
Variable-size result expected.
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_uint32(const char *name, uint32_t *u32)
uint32_t expected.
#define GNUNET_GNSRECORD_TYPE_PKEY
Record type for GNS zone transfer ("PKEY").
#define GNUNET_PQ_query_param_auto_from_type(x)
Generate fixed-size query parameter with size determined by variable type.
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_uint32(const uint32_t *x)
Generate query parameter for an uint32_t in host byte order.
static int database_setup(struct Plugin *plugin)
Initialize the database connections and associated data structures (create tables and indices as need...
static int res
static int namestore_postgres_iterate_records(void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, uint64_t serial, uint64_t limit, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
Iterate over the results for a particular key and zone in the datastore.
#define GNUNET_PQ_result_spec_auto_from_type(name, dst)
We expect a fixed-size result, with size determined by the type of * dst
PGconn * GNUNET_PQ_connect_with_cfg(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section)
Connect to a postgres database using the configuration option "CONFIG" in section.
Definition: pq_connect.c:112
#define GNUNET_PQ_PREPARED_STATEMENT_END
Terminator for prepared statement list.
GNUNET_NAMESTORE_RecordIterator iter
Function to call for each result.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
static void parse_result_call_iterator(void *cls, PGresult *res, unsigned int num_results)
A statement has been run.
helper functions for Postgres DB interactions
void * iter_cls
Iterator cls.
void * libgnunet_plugin_namestore_postgres_done(void *cls)
Exit point from the plugin.
Closure for parse_result_call_iterator.
int GNUNET_PQ_exec_statements(PGconn *connection, const struct GNUNET_PQ_ExecuteStatement *es)
Request execution of an array of statements es from Postgres.
Definition: pq_exec.c:77
static int namestore_postgres_lookup_records(void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, const char *label, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
Lookup records in the datastore for which we are the authority.
The transaction succeeded, and yielded one result.
Definition: gnunet_db_lib.h:57
static struct GNUNET_FS_PublishContext * pc
Handle to FS-publishing operation.
int(* lookup_records)(void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, const char *label, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
Lookup records in the datastore for which we are the authority.
configuration data
Definition: configuration.c:83
Handle for a plugin.
Definition: block.c:37
PGconn * dbh
Native Postgres database handle.
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_uint64(const uint64_t *x)
Generate query parameter for an uint16_t in host byte order.
void * iter_cls
Closure for iter.
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
Description of a DB query parameter.
Definition: gnunet_pq_lib.h:63
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_fixed_size(const void *ptr, size_t ptr_size)
Generate query parameter for a buffer ptr of ptr_size bytes.
#define GNUNET_PQ_EXECUTE_STATEMENT_END
Terminator for executable statement list.
const struct GNUNET_CRYPTO_EcdsaPrivateKey * zone_key
Zone key, NULL if part of record.
#define GNUNET_YES
Definition: gnunet_common.h:77
GNUNET_DB_QueryStatus
Status code returned from functions running database commands.
Definition: gnunet_db_lib.h:34
struct GNUNET_PQ_ExecuteStatement GNUNET_PQ_make_try_execute(const char *sql)
Create a struct GNUNET_PQ_ExecuteStatement where errors should be tolerated.
Definition: pq_exec.c:56
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_uint64(const char *name, uint64_t *u64)
uint64_t expected.
#define GNUNET_log_from(kind, comp,...)
The transaction succeeded, but yielded zero results.
Definition: gnunet_db_lib.h:52
int GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
uint32_t data
The data value.
int(* store_records)(void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, const char *label, unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd)
Store a record in the datastore for which we are the authority.
static size_t data_size
Number of bytes in data.
GNUNET_PEERSTORE_Processor iter
Iterator.
struct returned by the initialization function of the plugin
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
struct GNUNET_PQ_PreparedStatement GNUNET_PQ_make_prepare(const char *name, const char *sql, unsigned int num_args)
Create a struct GNUNET_PQ_PreparedStatement.
Definition: pq_prepare.c:39
int(* iterate_records)(void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, uint64_t serial, uint64_t limit, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
Iterate over the results for a particular zone in the datastore.
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
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
#define GNUNET_free(ptr)
Wrapper around free.
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:121