GNUnet  0.11.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
41 {
45  const struct GNUNET_CONFIGURATION_Handle *cfg;
46 
50  struct GNUNET_PQ_Context *dbh;
51 };
52 
53 
62 static int
64 {
65  struct GNUNET_PQ_ExecuteStatement es_temporary =
67  "CREATE TEMPORARY TABLE IF NOT EXISTS ns098records ("
68  " seq BIGSERIAL PRIMARY KEY,"
69  " zone_private_key BYTEA NOT NULL DEFAULT '',"
70  " pkey BYTEA DEFAULT '',"
71  " rvalue BYTEA NOT NULL DEFAULT '',"
72  " record_count INTEGER NOT NULL DEFAULT 0,"
73  " record_data BYTEA NOT NULL DEFAULT '',"
74  " label TEXT NOT NULL DEFAULT '',"
75  " CONSTRAINT zl UNIQUE (zone_private_key,label)"
76  ")"
77  "WITH OIDS");
78  struct GNUNET_PQ_ExecuteStatement es_default =
79  GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records ("
80  " seq BIGSERIAL PRIMARY KEY,"
81  " zone_private_key BYTEA NOT NULL DEFAULT '',"
82  " pkey BYTEA DEFAULT '',"
83  " rvalue BYTEA NOT NULL DEFAULT '',"
84  " record_count INTEGER NOT NULL DEFAULT 0,"
85  " record_data BYTEA NOT NULL DEFAULT '',"
86  " label TEXT NOT NULL DEFAULT '',"
87  " CONSTRAINT zl UNIQUE (zone_private_key,label)"
88  ")"
89  "WITH OIDS");
90  const struct GNUNET_PQ_ExecuteStatement *cr;
92 
93  if (GNUNET_YES ==
95  "namestore-postgres",
96  "TEMPORARY_TABLE"))
97  {
98  cr = &es_temporary;
99  }
100  else
101  {
102  cr = &es_default;
103  }
104 
105  if (GNUNET_YES ==
107  "namestore-postgres",
108  "ASYNC_COMMIT"))
109  sc = GNUNET_PQ_make_try_execute ("SET synchronous_commit TO off");
110 
111  {
112  struct GNUNET_PQ_ExecuteStatement es[] = {
113  *cr,
114  GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse "
115  "ON ns098records (zone_private_key,pkey)"),
116  GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter "
117  "ON ns098records (zone_private_key,seq)"),
118  GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_label "
119  "ON ns098records (label)"),
120  GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS zone_label "
121  "ON ns098records (zone_private_key,label)"),
122  sc,
124  };
125  struct GNUNET_PQ_PreparedStatement ps[] = {
126  GNUNET_PQ_make_prepare ("store_records",
127  "INSERT INTO ns098records"
128  " (zone_private_key, pkey, rvalue, record_count, record_data, label)"
129  " VALUES ($1, $2, $3, $4, $5, $6)"
130  " ON CONFLICT ON CONSTRAINT zl"
131  " DO UPDATE"
132  " SET pkey=$2,rvalue=$3,record_count=$4,record_data=$5"
133  " WHERE ns098records.zone_private_key = $1"
134  " AND ns098records.label = $6",
135  6),
136  GNUNET_PQ_make_prepare ("delete_records",
137  "DELETE FROM ns098records "
138  "WHERE zone_private_key=$1 AND label=$2",
139  2),
140  GNUNET_PQ_make_prepare ("zone_to_name",
141  "SELECT seq,record_count,record_data,label FROM ns098records"
142  " WHERE zone_private_key=$1 AND pkey=$2",
143  2),
144  GNUNET_PQ_make_prepare ("iterate_zone",
145  "SELECT seq,record_count,record_data,label FROM ns098records "
146  "WHERE zone_private_key=$1 AND seq > $2 ORDER BY seq ASC LIMIT $3",
147  3),
148  GNUNET_PQ_make_prepare ("iterate_all_zones",
149  "SELECT seq,record_count,record_data,label,zone_private_key"
150  " FROM ns098records WHERE seq > $1 ORDER BY seq ASC LIMIT $2",
151  2),
152  GNUNET_PQ_make_prepare ("lookup_label",
153  "SELECT seq,record_count,record_data,label "
154  "FROM ns098records WHERE zone_private_key=$1 AND label=$2",
155  2),
157  };
158 
159  plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
160  "namestore-postgres",
161  es,
162  ps);
163  }
164  if (NULL == plugin->dbh)
165  return GNUNET_SYSERR;
166  return GNUNET_OK;
167 }
168 
169 
181 static int
183  const struct
185  const char *label,
186  unsigned int rd_count,
187  const struct GNUNET_GNSRECORD_Data *rd)
188 {
189  struct Plugin *plugin = cls;
190  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
191  uint64_t rvalue;
192  uint32_t rd_count32 = (uint32_t) rd_count;
193  ssize_t data_size;
194 
195  memset (&pkey,
196  0,
197  sizeof(pkey));
198  for (unsigned int i = 0; i < rd_count; i++)
199  if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type)
200  {
201  GNUNET_break (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) ==
202  rd[i].data_size);
203  GNUNET_memcpy (&pkey,
204  rd[i].data,
205  rd[i].data_size);
206  break;
207  }
209  UINT64_MAX);
210  data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
211  rd);
212  if (data_size < 0)
213  {
214  GNUNET_break (0);
215  return GNUNET_SYSERR;
216  }
217  if (data_size >= UINT16_MAX)
218  {
219  GNUNET_break (0);
220  return GNUNET_SYSERR;
221  }
222  /* if record set is empty, delete existing records */
223  if (0 == rd_count)
224  {
225  struct GNUNET_PQ_QueryParam params[] = {
229  };
231 
233  "delete_records",
234  params);
237  {
238  GNUNET_break (0);
239  return GNUNET_SYSERR;
240  }
242  "postgres",
243  "Record deleted\n");
244  return GNUNET_OK;
245  }
246  /* otherwise, UPSERT (i.e. UPDATE if exists, otherwise INSERT) */
247  {
248  char data[data_size];
249  struct GNUNET_PQ_QueryParam params[] = {
253  GNUNET_PQ_query_param_uint32 (&rd_count32),
254  GNUNET_PQ_query_param_fixed_size (data, data_size),
257  };
259  ssize_t ret;
260 
261  ret = GNUNET_GNSRECORD_records_serialize (rd_count,
262  rd,
263  data_size,
264  data);
265  if ((ret < 0) ||
266  (data_size != ret))
267  {
268  GNUNET_break (0);
269  return GNUNET_SYSERR;
270  }
271 
273  "store_records",
274  params);
276  return GNUNET_SYSERR;
277  }
278  return GNUNET_OK;
279 }
280 
281 
286 {
291 
295  void *iter_cls;
296 
301 
306  uint64_t limit;
307 };
308 
309 
318 static void
320  PGresult *res,
321  unsigned int num_results)
322 {
323  struct ParserContext *pc = cls;
324 
325  if (NULL == pc->iter)
326  return; /* no need to do more work */
327  for (unsigned int i = 0; i < num_results; i++)
328  {
329  uint64_t serial;
330  void *data;
331  size_t data_size;
332  uint32_t record_count;
333  char *label;
335  struct GNUNET_PQ_ResultSpec rs_with_zone[] = {
336  GNUNET_PQ_result_spec_uint64 ("seq", &serial),
337  GNUNET_PQ_result_spec_uint32 ("record_count", &record_count),
338  GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size),
339  GNUNET_PQ_result_spec_string ("label", &label),
340  GNUNET_PQ_result_spec_auto_from_type ("zone_private_key", &zk),
342  };
343  struct GNUNET_PQ_ResultSpec rs_without_zone[] = {
344  GNUNET_PQ_result_spec_uint64 ("seq", &serial),
345  GNUNET_PQ_result_spec_uint32 ("record_count", &record_count),
346  GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size),
347  GNUNET_PQ_result_spec_string ("label", &label),
349  };
350  struct GNUNET_PQ_ResultSpec *rs;
351 
352  rs = (NULL == pc->zone_key) ? rs_with_zone : rs_without_zone;
353  if (GNUNET_YES !=
355  rs,
356  i))
357  {
358  GNUNET_break (0);
359  return;
360  }
361 
362  if (record_count > 64 * 1024)
363  {
364  /* sanity check, don't stack allocate far too much just
365  because database might contain a large value here */
366  GNUNET_break (0);
368  return;
369  }
370 
371  {
372  struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (record_count)];
373 
374  GNUNET_assert (0 != serial);
375  if (GNUNET_OK !=
377  data,
378  record_count,
379  rd))
380  {
381  GNUNET_break (0);
383  return;
384  }
385  pc->iter (pc->iter_cls,
386  serial,
387  (NULL == pc->zone_key) ? &zk : pc->zone_key,
388  label,
389  record_count,
390  rd);
391  }
393  }
394  pc->limit -= num_results;
395 }
396 
397 
408 static int
410  const struct
412  const char *label,
414  void *iter_cls)
415 {
416  struct Plugin *plugin = cls;
417  struct GNUNET_PQ_QueryParam params[] = {
421  };
422  struct ParserContext pc;
424 
425  if (NULL == zone)
426  {
427  GNUNET_break (0);
428  return GNUNET_SYSERR;
429  }
430  pc.iter = iter;
431  pc.iter_cls = iter_cls;
432  pc.zone_key = zone;
434  "lookup_label",
435  params,
437  &pc);
438  if (res < 0)
439  return GNUNET_SYSERR;
441  return GNUNET_NO;
442  return GNUNET_OK;
443 }
444 
445 
458 static int
460  const struct
462  uint64_t serial,
463  uint64_t limit,
465  void *iter_cls)
466 {
467  struct Plugin *plugin = cls;
469  struct ParserContext pc;
470 
471  pc.iter = iter;
472  pc.iter_cls = iter_cls;
473  pc.zone_key = zone;
474  pc.limit = limit;
475  if (NULL == zone)
476  {
477  struct GNUNET_PQ_QueryParam params_without_zone[] = {
481  };
482 
484  "iterate_all_zones",
485  params_without_zone,
487  &pc);
488  }
489  else
490  {
491  struct GNUNET_PQ_QueryParam params_with_zone[] = {
496  };
497 
499  "iterate_zone",
500  params_with_zone,
502  &pc);
503  }
504  if (res < 0)
505  return GNUNET_SYSERR;
506 
508  (pc.limit > 0))
509  return GNUNET_NO;
510  return GNUNET_OK;
511 }
512 
513 
525 static int
527  const struct
529  const struct
530  GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
532  void *iter_cls)
533 {
534  struct Plugin *plugin = cls;
535  struct GNUNET_PQ_QueryParam params[] = {
539  };
541  struct ParserContext pc;
542 
543  pc.iter = iter;
544  pc.iter_cls = iter_cls;
545  pc.zone_key = zone;
547  "zone_to_name",
548  params,
550  &pc);
551  if (res < 0)
552  return GNUNET_SYSERR;
553  return GNUNET_OK;
554 }
555 
556 
563 static void
565 {
566  GNUNET_PQ_disconnect (plugin->dbh);
567  plugin->dbh = NULL;
568 }
569 
570 
577 void *
579 {
580  static struct Plugin plugin;
581  const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
583 
584  if (NULL != plugin.cfg)
585  return NULL; /* can only initialize once! */
586  memset (&plugin, 0, sizeof(struct Plugin));
587  plugin.cfg = cfg;
588  if (GNUNET_OK != database_setup (&plugin))
589  {
590  database_shutdown (&plugin);
591  return NULL;
592  }
594  api->cls = &plugin;
600  "Postgres namestore plugin running\n");
601  return api;
602 }
603 
604 
611 void *
613 {
615  struct Plugin *plugin = api->cls;
616 
617  database_shutdown (plugin);
618  plugin->cfg = NULL;
619  GNUNET_free (api);
621  "Postgres namestore plugin is finished\n");
622  return NULL;
623 }
624 
625 
626 /* end of plugin_namestore_postgres.c */
struct GNUNET_PQ_Context * GNUNET_PQ_connect_with_cfg(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const struct GNUNET_PQ_ExecuteStatement *es, const struct GNUNET_PQ_PreparedStatement *ps)
Connect to a postgres database using the configuration option "CONFIG" in section.
Definition: pq_connect.c:217
void GNUNET_PQ_disconnect(struct GNUNET_PQ_Context *db)
Disconnect from the database, destroying the prepared statements and releasing other associated resou...
Definition: pq_connect.c:246
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:36
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.
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:209
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
#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.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
#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.
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,...)
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:47
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.
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:96
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.
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 char * plugin
Solver plugin name as string.
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
#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.
static struct GNUNET_FS_SearchContext * sc
Definition: gnunet-search.c:37
void * libgnunet_plugin_namestore_postgres_done(void *cls)
Exit point from the plugin.
Closure for parse_result_call_iterator.
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:58
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 connnection using the given para...
Definition: pq_eval.c:164
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:85
Handle for a plugin.
Definition: block.c:37
struct GNUNET_PQ_Context * 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:64
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:55
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:53
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.
GNUNET_PEERSTORE_Processor iter
Iterator.
struct returned by the initialization function of the plugin
Handle to Postgres database.
Definition: pq.h:34
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:38
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:151
#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:130