gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnunet] branch master updated (8ed3ad85f -> 195fd08b9)


From: gnunet
Subject: [GNUnet-SVN] [gnunet] branch master updated (8ed3ad85f -> 195fd08b9)
Date: Fri, 11 Oct 2019 23:38:26 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository gnunet.

    from 8ed3ad85f we probably want to actually test the sync
     new e3e21acb2 libgnunetpq API change to fix #5733
     new 195fd08b9 add GNUNET_PQ_reconnect_if_down

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/datacache/plugin_datacache_postgres.c        |  25 +--
 src/datastore/plugin_datastore_postgres.c        |  20 +--
 src/include/gnunet_pq_lib.h                      | 142 +++++++++++------
 src/namecache/plugin_namecache_postgres.c        |  38 ++---
 src/namestore/plugin_namestore_postgres.c        |  64 +++-----
 src/pq/Makefile.am                               |   2 +-
 src/pq/pq.c                                      |  43 +++---
 src/{util/test_crypto_hash_context.c => pq/pq.h} |  59 ++++---
 src/pq/pq_connect.c                              | 183 ++++++++++++++++++----
 src/pq/pq_eval.c                                 |  59 ++++---
 src/pq/pq_exec.c                                 |  15 +-
 src/pq/pq_prepare.c                              |  39 ++++-
 src/pq/pq_result_helper.c                        |   2 +-
 src/pq/test_pq.c                                 | 186 +++++++++++------------
 14 files changed, 517 insertions(+), 360 deletions(-)
 copy src/{util/test_crypto_hash_context.c => pq/pq.h} (56%)

diff --git a/src/datacache/plugin_datacache_postgres.c 
b/src/datacache/plugin_datacache_postgres.c
index 59dff9067..c532550ae 100644
--- a/src/datacache/plugin_datacache_postgres.c
+++ b/src/datacache/plugin_datacache_postgres.c
@@ -48,7 +48,7 @@ struct Plugin
   /**
    * Native Postgres database handle.
    */
-  PGconn *dbh;
+  struct GNUNET_PQ_Context *dbh;
 
   /**
    * Number of key-value pairs in the database.
@@ -122,26 +122,11 @@ init_connection (struct Plugin *plugin)
   };
 
   plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg,
-                                            "datacache-postgres");
+                                            "datacache-postgres",
+                                            es,
+                                            ps);
   if (NULL == plugin->dbh)
     return GNUNET_SYSERR;
-  if (GNUNET_OK !=
-      GNUNET_PQ_exec_statements (plugin->dbh,
-                                 es))
-  {
-    PQfinish (plugin->dbh);
-    plugin->dbh = NULL;
-    return GNUNET_SYSERR;
-  }
-
-  if (GNUNET_OK !=
-      GNUNET_PQ_prepare_statements (plugin->dbh,
-                                    ps))
-  {
-    PQfinish (plugin->dbh);
-    plugin->dbh = NULL;
-    return GNUNET_SYSERR;
-  }
   return GNUNET_OK;
 }
 
@@ -710,7 +695,7 @@ libgnunet_plugin_datacache_postgres_done (void *cls)
   struct GNUNET_DATACACHE_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
 
-  PQfinish (plugin->dbh);
+  GNUNET_PQ_disconnect (plugin->dbh);
   GNUNET_free (plugin);
   GNUNET_free (api);
   return NULL;
diff --git a/src/datastore/plugin_datastore_postgres.c 
b/src/datastore/plugin_datastore_postgres.c
index 181cf8cf8..0811edfd7 100644
--- a/src/datastore/plugin_datastore_postgres.c
+++ b/src/datastore/plugin_datastore_postgres.c
@@ -54,7 +54,7 @@ struct Plugin
   /**
    * Native Postgres database handle.
    */
-  PGconn *dbh;
+  struct GNUNET_PQ_Context *dbh;
 };
 
 
@@ -172,21 +172,11 @@ init_connection (struct Plugin *plugin)
 #undef RESULT_COLUMNS
 
   plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg,
-                                            "datastore-postgres");
+                                            "datastore-postgres",
+                                            es,
+                                            ps);
   if (NULL == plugin->dbh)
     return GNUNET_SYSERR;
-
-  if ((GNUNET_OK !=
-       GNUNET_PQ_exec_statements (plugin->dbh,
-                                  es)) ||
-      (GNUNET_OK !=
-       GNUNET_PQ_prepare_statements (plugin->dbh,
-                                     ps)))
-  {
-    PQfinish (plugin->dbh);
-    plugin->dbh = NULL;
-    return GNUNET_SYSERR;
-  }
   return GNUNET_OK;
 }
 
@@ -974,7 +964,7 @@ libgnunet_plugin_datastore_postgres_done (void *cls)
   struct GNUNET_DATASTORE_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
 
-  PQfinish (plugin->dbh);
+  GNUNET_PQ_disconnect (plugin->dbh);
   GNUNET_free (plugin);
   GNUNET_free (api);
   return NULL;
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h
index 6c576c8ab..2aea77b7f 100644
--- a/src/include/gnunet_pq_lib.h
+++ b/src/include/gnunet_pq_lib.h
@@ -46,15 +46,16 @@
  * @param scratch_length number of entries left in @a scratch
  * @return -1 on error, number of offsets used in @a scratch otherwise
  */
-typedef int (*GNUNET_PQ_QueryConverter) (void *cls,
-                                         const void *data,
-                                         size_t data_len,
-                                         void *param_values[],
-                                         int param_lengths[],
-                                         int param_formats[],
-                                         unsigned int param_length,
-                                         void *scratch[],
-                                         unsigned int scratch_length);
+typedef int
+(*GNUNET_PQ_QueryConverter) (void *cls,
+                             const void *data,
+                             size_t data_len,
+                             void *param_values[],
+                             int param_lengths[],
+                             int param_formats[],
+                             unsigned int param_length,
+                             void *scratch[],
+                             unsigned int scratch_length);
 
 
 /**
@@ -214,12 +215,13 @@ GNUNET_PQ_query_param_uint64 (const uint64_t *x);
  *   #GNUNET_YES if all results could be extracted
  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
  */
-typedef int (*GNUNET_PQ_ResultConverter) (void *cls,
-                                          PGresult *result,
-                                          int row,
-                                          const char *fname,
-                                          size_t *dst_size,
-                                          void *dst);
+typedef int
+(*GNUNET_PQ_ResultConverter) (void *cls,
+                              PGresult *result,
+                              int row,
+                              const char *fname,
+                              size_t *dst_size,
+                              void *dst);
 
 
 /**
@@ -229,7 +231,9 @@ typedef int (*GNUNET_PQ_ResultConverter) (void *cls,
  * @param cls closure
  * @param rd result data to clean up
  */
-typedef void (*GNUNET_PQ_ResultCleanup) (void *cls, void *rd);
+typedef void
+(*GNUNET_PQ_ResultCleanup) (void *cls,
+                            void *rd);
 
 
 /**
@@ -419,17 +423,23 @@ GNUNET_PQ_result_spec_uint64 (const char *name, uint64_t 
*u64);
 
 /* ************************* pq.c functions ************************ */
 
+/**
+ * Postgres context.
+ */
+struct GNUNET_PQ_Context;
+
+
 /**
  * Execute a prepared statement.
  *
- * @param db_conn database connection
+ * @param db database context
  * @param name name of the prepared statement
  * @param params parameters to the statement
  * @return postgres result
  * @deprecated (should become an internal API)
  */
 PGresult *
-GNUNET_PQ_exec_prepared (PGconn *db_conn,
+GNUNET_PQ_exec_prepared (struct GNUNET_PQ_Context *db,
                          const char *name,
                          const struct GNUNET_PQ_QueryParam *params);
 
@@ -468,7 +478,7 @@ GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs);
  * Check the @a result's error code to see what happened.
  * Also logs errors.
  *
- * @param connection connection to execute the statement in
+ * @param db database to execute the statement in
  * @param statement_name name of the statement that created @a result
  * @param result result to check
  * @return status code from the result, mapping PQ status
@@ -478,7 +488,7 @@ GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs);
  * @deprecated (low level, let's see if we can do with just the high-level 
functions)
  */
 enum GNUNET_DB_QueryStatus
-GNUNET_PQ_eval_result (PGconn *connection,
+GNUNET_PQ_eval_result (struct GNUNET_PQ_Context *db,
                        const char *statement_name,
                        PGresult *result);
 
@@ -488,7 +498,7 @@ GNUNET_PQ_eval_result (PGconn *connection,
  * statement in @a connnection using the given @a params.  Returns the
  * resulting session state.
  *
- * @param connection connection to execute the statement in
+ * @param db database to execute the statement with
  * @param statement_name name of the statement
  * @param params parameters to give to the statement 
(#GNUNET_PQ_query_param_end-terminated)
  * @return status code from the result, mapping PQ status
@@ -500,7 +510,7 @@ GNUNET_PQ_eval_result (PGconn *connection,
  *         zero; if INSERT was successful, we return one.
  */
 enum GNUNET_DB_QueryStatus
-GNUNET_PQ_eval_prepared_non_select (PGconn *connection,
+GNUNET_PQ_eval_prepared_non_select (struct GNUNET_PQ_Context *db,
                                     const char *statement_name,
                                     const struct GNUNET_PQ_QueryParam *params);
 
@@ -513,9 +523,10 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection,
  * @param result the postgres result
  * @param num_result the number of results in @a result
  */
-typedef void (*GNUNET_PQ_PostgresResultHandler) (void *cls,
-                                                 PGresult *result,
-                                                 unsigned int num_results);
+typedef void
+(*GNUNET_PQ_PostgresResultHandler) (void *cls,
+                                    PGresult *result,
+                                    unsigned int num_results);
 
 
 /**
@@ -525,7 +536,7 @@ typedef void (*GNUNET_PQ_PostgresResultHandler) (void *cls,
  * status including the number of results given to @a rh (possibly zero).
  * @a rh will not have been called if the return value is negative.
  *
- * @param connection connection to execute the statement in
+ * @param db database to execute the statement with
  * @param statement_name name of the statement
  * @param params parameters to give to the statement 
(#GNUNET_PQ_query_param_end-terminated)
  * @param rh function to call with the result set, NULL to ignore
@@ -534,7 +545,7 @@ typedef void (*GNUNET_PQ_PostgresResultHandler) (void *cls,
  *         codes to `enum GNUNET_DB_QueryStatus`.
  */
 enum GNUNET_DB_QueryStatus
-GNUNET_PQ_eval_prepared_multi_select (PGconn *connection,
+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,
@@ -549,7 +560,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection,
  * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT.  Returns the
  * resulting session status.
  *
- * @param connection connection to execute the statement in
+ * @param db database to execute the statement with
  * @param statement_name name of the statement
  * @param params parameters to give to the statement 
(#GNUNET_PQ_query_param_end-terminated)
  * @param[in,out] rs result specification to use for storing the result of the 
query
@@ -557,11 +568,11 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection,
  *         codes to `enum GNUNET_DB_QueryStatus`.
  */
 enum GNUNET_DB_QueryStatus
-GNUNET_PQ_eval_prepared_singleton_select (
-  PGconn *connection,
-  const char *statement_name,
-  const struct GNUNET_PQ_QueryParam *params,
-  struct GNUNET_PQ_ResultSpec *rs);
+GNUNET_PQ_eval_prepared_singleton_select (struct GNUNET_PQ_Context *db,
+                                          const char *statement_name,
+                                          const struct
+                                          GNUNET_PQ_QueryParam *params,
+                                          struct GNUNET_PQ_ResultSpec *rs);
 
 
 /* ******************** pq_prepare.c functions ************** */
@@ -587,6 +598,7 @@ struct GNUNET_PQ_PreparedStatement
    * Number of arguments included in @e sql.
    */
   unsigned int num_arguments;
+
 };
 
 
@@ -616,14 +628,14 @@ GNUNET_PQ_make_prepare (const char *name,
 /**
  * Request creation of prepared statements @a ps from Postgres.
  *
- * @param connection connection to prepare the statements for
+ * @param db database to prepare the statements for
  * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared
  *            statements.
  * @return #GNUNET_OK on success,
  *         #GNUNET_SYSERR on error
  */
 int
-GNUNET_PQ_prepare_statements (PGconn *connection,
+GNUNET_PQ_prepare_statements (struct GNUNET_PQ_Context *db,
                               const struct GNUNET_PQ_PreparedStatement *ps);
 
 
@@ -681,14 +693,14 @@ GNUNET_PQ_make_try_execute (const char *sql);
 /**
  * Request execution of an array of statements @a es from Postgres.
  *
- * @param connection connection to execute the statements over
+ * @param pq database to execute the statements in
  * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared
  *            statements.
  * @return #GNUNET_OK on success (modulo statements where errors can be 
ignored)
  *         #GNUNET_SYSERR on error
  */
 int
-GNUNET_PQ_exec_statements (PGconn *connection,
+GNUNET_PQ_exec_statements (struct GNUNET_PQ_Context *db,
                            const struct GNUNET_PQ_ExecuteStatement *es);
 
 
@@ -698,26 +710,70 @@ GNUNET_PQ_exec_statements (PGconn *connection,
 /**
  * Create a connection to the Postgres database using @a config_str
  * for the configuration.  Initialize logging via GNUnet's log
- * routines and disable Postgres's logger.
+ * routines and disable Postgres's logger.  Also ensures that the
+ * statements in @a es are executed whenever we (re)connect to the
+ * database, and that the prepared statements in @a ps are "ready".
+ * If statements in @es fail that were created with
+ * #GNUNET_PQ_make_execute(), then the entire operation fails.
  *
  * @param config_str configuration to use
+ * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated
+ *            array of statements to execute upon EACH connection, can be NULL
+ * @param ps array of prepared statements to prepare, can be NULL
  * @return NULL on error
  */
-PGconn *
-GNUNET_PQ_connect (const char *config_str);
+struct GNUNET_PQ_Context *
+GNUNET_PQ_connect (const char *config_str,
+                   const struct GNUNET_PQ_ExecuteStatement *es,
+                   const struct GNUNET_PQ_PreparedStatement *ps);
 
 
 /**
  * Connect to a postgres database using the configuration
- * option "CONFIG" in @a section.
+ * option "CONFIG" in @a section.  Also ensures that the
+ * statements in @a es are executed whenever we (re)connect to the
+ * database, and that the prepared statements in @a ps are "ready".
  *
  * @param cfg configuration
  * @param section configuration section to use to get Postgres configuration 
options
+ * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated
+ *            array of statements to execute upon EACH connection, can be NULL
+ * @param ps array of prepared statements to prepare, can be NULL
  * @return the postgres handle, NULL on error
  */
-PGconn *
+struct GNUNET_PQ_Context *
 GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                            const char *section);
+                            const char *section,
+                            const struct GNUNET_PQ_ExecuteStatement *es,
+                            const struct GNUNET_PQ_PreparedStatement *ps);
+
+
+/**
+ * Reinitialize the database @a db if the connection is down.
+ *
+ * @param db database connection to reinitialize
+ */
+void
+GNUNET_PQ_reconnect_if_down (struct GNUNET_PQ_Context *db);
+
+
+/**
+ * Reinitialize the database @a db.
+ *
+ * @param db database connection to reinitialize
+ */
+void
+GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db);
+
+
+/**
+ * Disconnect from the database, destroying the prepared statements
+ * and releasing other associated resources.
+ *
+ * @param db database handle to disconnect (will be free'd)
+ */
+void
+GNUNET_PQ_disconnect (struct GNUNET_PQ_Context *db);
 
 
 #endif /* GNUNET_PQ_LIB_H_ */
diff --git a/src/namecache/plugin_namecache_postgres.c 
b/src/namecache/plugin_namecache_postgres.c
index e4b360ef2..35bf5c2ff 100644
--- a/src/namecache/plugin_namecache_postgres.c
+++ b/src/namecache/plugin_namecache_postgres.c
@@ -42,9 +42,9 @@ struct Plugin
   const struct GNUNET_CONFIGURATION_Handle *cfg;
 
   /**
-   * Native Postgres database handle.
+   * Postgres database handle.
    */
-  PGconn *dbh;
+  struct GNUNET_PQ_Context *dbh;
 };
 
 
@@ -75,10 +75,6 @@ database_setup (struct Plugin *plugin)
                             "WITH OIDS");
   const struct GNUNET_PQ_ExecuteStatement *cr;
 
-  plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
-                                            "namecache-postgres");
-  if (NULL == plugin->dbh)
-    return GNUNET_SYSERR;
   if (GNUNET_YES ==
       GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
                                             "namecache-postgres",
@@ -90,7 +86,6 @@ database_setup (struct Plugin *plugin)
   {
     cr = &es_default;
   }
-
   {
     struct GNUNET_PQ_ExecuteStatement es[] = {
       *cr,
@@ -100,18 +95,6 @@ database_setup (struct Plugin *plugin)
         "CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)"),
       GNUNET_PQ_EXECUTE_STATEMENT_END
     };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_exec_statements (plugin->dbh,
-                                   es))
-    {
-      PQfinish (plugin->dbh);
-      plugin->dbh = NULL;
-      return GNUNET_SYSERR;
-    }
-  }
-
-  {
     struct GNUNET_PQ_PreparedStatement ps[] = {
       GNUNET_PQ_make_prepare ("cache_block",
                               "INSERT INTO ns096blocks (query, block, 
expiration_time) VALUES "
@@ -128,16 +111,13 @@ database_setup (struct Plugin *plugin)
       GNUNET_PQ_PREPARED_STATEMENT_END
     };
 
-    if (GNUNET_OK !=
-        GNUNET_PQ_prepare_statements (plugin->dbh,
-                                      ps))
-    {
-      PQfinish (plugin->dbh);
-      plugin->dbh = NULL;
-      return GNUNET_SYSERR;
-    }
+    plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
+                                              "namecache-postgres",
+                                              es,
+                                              ps);
   }
-
+  if (NULL == plugin->dbh)
+    return GNUNET_SYSERR;
   return GNUNET_OK;
 }
 
@@ -311,7 +291,7 @@ namecache_postgres_lookup_block (void *cls,
 static void
 database_shutdown (struct Plugin *plugin)
 {
-  PQfinish (plugin->dbh);
+  GNUNET_PQ_disconnect (plugin->dbh);
   plugin->dbh = NULL;
 }
 
diff --git a/src/namestore/plugin_namestore_postgres.c 
b/src/namestore/plugin_namestore_postgres.c
index 5148ca0f5..23893538b 100644
--- a/src/namestore/plugin_namestore_postgres.c
+++ b/src/namestore/plugin_namestore_postgres.c
@@ -45,9 +45,9 @@ struct Plugin
   const struct GNUNET_CONFIGURATION_Handle *cfg;
 
   /**
-   * Native Postgres database handle.
+   * Postgres database handle.
    */
-  PGconn *dbh;
+  struct GNUNET_PQ_Context *dbh;
 };
 
 
@@ -88,30 +88,8 @@ database_setup (struct Plugin *plugin)
                             ")"
                             "WITH OIDS");
   const struct GNUNET_PQ_ExecuteStatement *cr;
+  struct GNUNET_PQ_ExecuteStatement sc = GNUNET_PQ_EXECUTE_STATEMENT_END;
 
-  plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
-                                            "namestore-postgres");
-  if (NULL == plugin->dbh)
-    return GNUNET_SYSERR;
-  if (GNUNET_YES ==
-      GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
-                                            "namestore-postgres",
-                                            "ASYNC_COMMIT"))
-  {
-    struct GNUNET_PQ_ExecuteStatement es[] = {
-      GNUNET_PQ_make_try_execute ("SET synchronous_commit TO off"),
-      GNUNET_PQ_EXECUTE_STATEMENT_END
-    };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_exec_statements (plugin->dbh,
-                                   es))
-    {
-      PQfinish (plugin->dbh);
-      plugin->dbh = NULL;
-      return GNUNET_SYSERR;
-    }
-  }
   if (GNUNET_YES ==
       GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
                                             "namestore-postgres",
@@ -124,6 +102,12 @@ database_setup (struct Plugin *plugin)
     cr = &es_default;
   }
 
+  if (GNUNET_YES ==
+      GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
+                                            "namestore-postgres",
+                                            "ASYNC_COMMIT"))
+    sc = GNUNET_PQ_make_try_execute ("SET synchronous_commit TO off");
+
   {
     struct GNUNET_PQ_ExecuteStatement es[] = {
       *cr,
@@ -135,20 +119,9 @@ database_setup (struct Plugin *plugin)
                                   "ON ns098records (label)"),
       GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS zone_label "
                                   "ON ns098records (zone_private_key,label)"),
+      sc,
       GNUNET_PQ_EXECUTE_STATEMENT_END
     };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_exec_statements (plugin->dbh,
-                                   es))
-    {
-      PQfinish (plugin->dbh);
-      plugin->dbh = NULL;
-      return GNUNET_SYSERR;
-    }
-  }
-
-  {
     struct GNUNET_PQ_PreparedStatement ps[] = {
       GNUNET_PQ_make_prepare ("store_records",
                               "INSERT INTO ns098records"
@@ -183,16 +156,13 @@ database_setup (struct Plugin *plugin)
       GNUNET_PQ_PREPARED_STATEMENT_END
     };
 
-    if (GNUNET_OK !=
-        GNUNET_PQ_prepare_statements (plugin->dbh,
-                                      ps))
-    {
-      PQfinish (plugin->dbh);
-      plugin->dbh = NULL;
-      return GNUNET_SYSERR;
-    }
+    plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
+                                              "namestore-postgres",
+                                              es,
+                                              ps);
   }
-
+  if (NULL == plugin->dbh)
+    return GNUNET_SYSERR;
   return GNUNET_OK;
 }
 
@@ -593,7 +563,7 @@ namestore_postgres_zone_to_name (void *cls,
 static void
 database_shutdown (struct Plugin *plugin)
 {
-  PQfinish (plugin->dbh);
+  GNUNET_PQ_disconnect (plugin->dbh);
   plugin->dbh = NULL;
 }
 
diff --git a/src/pq/Makefile.am b/src/pq/Makefile.am
index 9270e6fe0..750a1d48d 100644
--- a/src/pq/Makefile.am
+++ b/src/pq/Makefile.am
@@ -22,7 +22,7 @@ libgnunetpq_la_LIBADD = -lpq \
 libgnunetpq_la_LDFLAGS = \
  $(POSTGRESQL_LDFLAGS) \
  $(GN_LIB_LDFLAGS) \
-  -version-info 0:0:0
+  -version-info 1:0:0
 
 if ENABLE_TEST_RUN
 TESTS = \
diff --git a/src/pq/pq.c b/src/pq/pq.c
index 7e97c8f72..d2b9a6174 100644
--- a/src/pq/pq.c
+++ b/src/pq/pq.c
@@ -1,6 +1,6 @@
 /*
    This file is part of GNUnet
-   Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+   Copyright (C) 2014, 2015, 2016, 2017, 2019 GNUnet e.V.
 
    GNUnet is free software: you can redistribute it and/or modify it
    under the terms of the GNU Affero General Public License as published
@@ -25,33 +25,30 @@
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_pq_lib.h"
-
+#include "pq.h"
 
 /**
  * Execute a prepared statement.
  *
- * @param db_conn database connection
+ * @param db database handle
  * @param name name of the prepared statement
  * @param params parameters to the statement
  * @return postgres result
  */
 PGresult *
-GNUNET_PQ_exec_prepared (PGconn *db_conn,
+GNUNET_PQ_exec_prepared (struct GNUNET_PQ_Context *db,
                          const char *name,
                          const struct GNUNET_PQ_QueryParam *params)
 {
   unsigned int len;
-  unsigned int i;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Running prepared statement `%s' on %p\n",
               name,
-              db_conn);
+              db);
   /* count the number of parameters */
   len = 0;
-  for (i = 0; 0 != params[i].num_params; i++)
+  for (unsigned int i = 0; 0 != params[i].num_params; i++)
     len += params[i].num_params;
 
   /* new scope to allow stack allocation without alloca */
@@ -67,10 +64,11 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn,
     unsigned int soff;
     PGresult *res;
     int ret;
+    ConnStatusType status;
 
     off = 0;
     soff = 0;
-    for (i = 0; 0 != params[i].num_params; i++)
+    for (unsigned int i = 0; 0 != params[i].num_params; i++)
     {
       const struct GNUNET_PQ_QueryParam *x = &params[i];
 
@@ -97,13 +95,24 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn,
                      "pq",
                      "Executing prepared SQL statement `%s'\n",
                      name);
-    res = PQexecPrepared (db_conn,
+    res = PQexecPrepared (db->conn,
                           name,
                           len,
                           (const char **) param_values,
                           param_lengths,
                           param_formats,
                           1);
+    if ( (PGRES_COMMAND_OK != PQresultStatus (res)) &&
+         (CONNECTION_OK != (status = PQstatus (db->conn))) )
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                       "pq",
+                       "Database disconnected on SQL statement `%s' 
(reconnecting)\n",
+                       name);
+      GNUNET_PQ_reconnect (db);
+      res = NULL;
+    }
+
     for (off = 0; off < soff; off++)
       GNUNET_free (scratch[off]);
     return res;
@@ -120,9 +129,7 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn,
 void
 GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs)
 {
-  unsigned int i;
-
-  for (i = 0; NULL != rs[i].conv; i++)
+  for (unsigned int i = 0; NULL != rs[i].conv; i++)
     if (NULL != rs[i].cleaner)
       rs[i].cleaner (rs[i].cls,
                      rs[i].dst);
@@ -145,12 +152,12 @@ GNUNET_PQ_extract_result (PGresult *result,
                           struct GNUNET_PQ_ResultSpec *rs,
                           int row)
 {
-  unsigned int i;
-  int ret;
-
-  for (i = 0; NULL != rs[i].conv; i++)
+  if (NULL == result)
+    return GNUNET_SYSERR;
+  for (unsigned int i = 0; NULL != rs[i].conv; i++)
   {
     struct GNUNET_PQ_ResultSpec *spec;
+    int ret;
 
     spec = &rs[i];
     ret = spec->conv (spec->cls,
diff --git a/src/util/test_crypto_hash_context.c b/src/pq/pq.h
similarity index 56%
copy from src/util/test_crypto_hash_context.c
copy to src/pq/pq.h
index d744b52b4..b30f4f0d4 100644
--- a/src/util/test_crypto_hash_context.c
+++ b/src/pq/pq.h
@@ -1,6 +1,6 @@
 /*
    This file is part of GNUnet
-   Copyright (C) 2014 GNUnet e.V.
+   Copyright (C) 2017, 2019 GNUnet e.V.
 
    GNUnet is free software: you can redistribute it and/or modify it
    under the terms of the GNU Affero General Public License as published
@@ -18,31 +18,40 @@
      SPDX-License-Identifier: AGPL3.0-or-later
  */
 /**
- * @file util/test_crypto_hash_context.c
- * @brief test case for incremental hashing
- * @author Florian Dold
+ * @file pq/pq.h
+ * @brief shared internal data structures of libgnunetpq
+ * @author Christian Grothoff
  */
-#include "platform.h"
-#include "gnunet_util_lib.h"
+#ifndef PQ_H
+#define PQ_H
 
-#define LEN 1234
+#include "gnunet_util_lib.h"
+#include "gnunet_pq_lib.h"
 
-int main ()
+/**
+ * Handle to Postgres database.
+ */
+struct GNUNET_PQ_Context
 {
-  char data[1234];
-  struct GNUNET_HashCode hc1;
-  struct GNUNET_HashCode hc2;
-  struct GNUNET_HashContext *hctx;
-
-  memset (data, 42, LEN);
-
-  hctx = GNUNET_CRYPTO_hash_context_start ();
-  GNUNET_CRYPTO_hash_context_read (hctx, data, LEN);
-  GNUNET_CRYPTO_hash_context_finish (hctx, &hc1);
-
-  GNUNET_CRYPTO_hash (data, LEN, &hc2);
-
-  if (0 == memcmp (&hc1, &hc2, sizeof(struct GNUNET_HashCode)))
-    return 0;
-  return 1;
-}
+  /**
+   * Actual connection.
+   */
+  PGconn *conn;
+
+  /**
+   * Statements to execute upon connection.
+   */
+  struct GNUNET_PQ_ExecuteStatement *es;
+
+  /**
+   * Prepared statements.
+   */
+  struct GNUNET_PQ_PreparedStatement *ps;
+
+  /**
+   * Configuration to use to connect to the DB.
+   */
+  char *config_str;
+};
+
+#endif
diff --git a/src/pq/pq_connect.c b/src/pq/pq_connect.c
index 79b9d6107..882df4f89 100644
--- a/src/pq/pq_connect.c
+++ b/src/pq/pq_connect.c
@@ -1,6 +1,6 @@
 /*
    This file is part of GNUnet
-   Copyright (C) 2017 GNUnet e.V.
+   Copyright (C) 2017, 2019 GNUnet e.V.
 
    GNUnet is free software: you can redistribute it and/or modify it
    under the terms of the GNU Affero General Public License as published
@@ -23,8 +23,7 @@
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_pq_lib.h"
+#include "pq.h"
 
 
 /**
@@ -40,12 +39,14 @@ pq_notice_receiver_cb (void *arg,
                        const PGresult *res)
 {
   /* do nothing, intentionally */
+  (void) arg;
+  (void) res;
 }
 
 
 /**
  * Function called by libpq whenever it wants to log something.
- * We log those using the Taler logger.
+ * We log those using the GNUnet logger.
  *
  * @param arg the SQL connection that was used
  * @param message information about some libpq event
@@ -54,6 +55,7 @@ static void
 pq_notice_processor_cb (void *arg,
                         const char *message)
 {
+  (void) arg;
   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
                    "pq",
                    "%s",
@@ -64,68 +66,189 @@ pq_notice_processor_cb (void *arg,
 /**
  * Create a connection to the Postgres database using @a config_str
  * for the configuration.  Initialize logging via GNUnet's log
- * routines and disable Postgres's logger.
+ * routines and disable Postgres's logger.  Also ensures that the
+ * statements in @a es are executed whenever we (re)connect to the
+ * database, and that the prepared statements in @a ps are "ready".
+ * If statements in @es fail that were created with
+ * #GNUNET_PQ_make_execute(), then the entire operation fails.
+ *
+ * The caller MUST ensure that @a es and @a ps remain allocated and
+ * initialized in memory until #GNUNET_PQ_disconnect() is called,
+ * as they may be needed repeatedly and no copy will be made.
  *
  * @param config_str configuration to use
+ * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated
+ *            array of statements to execute upon EACH connection, can be NULL
+ * @param ps array of prepared statements to prepare, can be NULL
  * @return NULL on error
  */
-PGconn *
-GNUNET_PQ_connect (const char *config_str)
+struct GNUNET_PQ_Context *
+GNUNET_PQ_connect (const char *config_str,
+                   const struct GNUNET_PQ_ExecuteStatement *es,
+                   const struct GNUNET_PQ_PreparedStatement *ps)
 {
-  PGconn *conn;
+  struct GNUNET_PQ_Context *db;
+  unsigned int elen = 0;
+  unsigned int plen = 0;
+
+  if (NULL != es)
+    while (NULL != es[elen].sql)
+      elen++;
+  if (NULL != ps)
+    while (NULL != ps[plen].name)
+      plen++;
+
+  db = GNUNET_new (struct GNUNET_PQ_Context);
+  db->config_str = GNUNET_strdup (config_str);
+  if (0 != elen)
+  {
+    db->es = GNUNET_new_array (elen + 1,
+                               struct GNUNET_PQ_ExecuteStatement);
+    memcpy (db->es,
+            es,
+            elen * sizeof (struct GNUNET_PQ_ExecuteStatement));
+  }
+  if (0 != plen)
+  {
+    db->ps = GNUNET_new_array (plen + 1,
+                               struct GNUNET_PQ_PreparedStatement);
+    memcpy (db->ps,
+            ps,
+            plen * sizeof (struct GNUNET_PQ_PreparedStatement));
+  }
+  GNUNET_PQ_reconnect (db);
+  if (NULL == db->conn)
+  {
+    GNUNET_free (db->config_str);
+    GNUNET_free (db);
+    return NULL;
+  }
+  return db;
+}
+
+
+/**
+ * Reinitialize the database @a db if the connection is down.
+ *
+ * @param db database connection to reinitialize
+ */
+void
+GNUNET_PQ_reconnect_if_down (struct GNUNET_PQ_Context *db)
+{
+  if (CONNECTION_BAD != PQstatus (db->conn))
+    return;
+  GNUNET_PQ_reconnect (db);
+}
+
 
-  conn = PQconnectdb (config_str);
-  if ((NULL == conn) ||
-      (CONNECTION_OK !=
-       PQstatus (conn)))
+/**
+ * Reinitialize the database @a db.
+ *
+ * @param db database connection to reinitialize
+ */
+void
+GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db)
+{
+  if (NULL != db->conn)
+    PQfinish (db->conn);
+  db->conn = PQconnectdb (db->config_str);
+  if ((NULL == db->conn) ||
+      (CONNECTION_OK != PQstatus (db->conn)))
   {
     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
                      "pq",
                      "Database connection to '%s' failed: %s\n",
-                     config_str,
-                     (NULL != conn) ?
-                     PQerrorMessage (conn)
+                     db->config_str,
+                     (NULL != db->conn) ?
+                     PQerrorMessage (db->conn)
                      : "PQconnectdb returned NULL");
-    if (NULL != conn)
-      PQfinish (conn);
-    return NULL;
+    if (NULL != db->conn)
+    {
+      PQfinish (db->conn);
+      db->conn = NULL;
+    }
+    return;
   }
-  PQsetNoticeReceiver (conn,
+  PQsetNoticeReceiver (db->conn,
                        &pq_notice_receiver_cb,
-                       conn);
-  PQsetNoticeProcessor (conn,
+                       db);
+  PQsetNoticeProcessor (db->conn,
                         &pq_notice_processor_cb,
-                        conn);
-  return conn;
+                        db);
+  if ( (NULL != db->es) &&
+       (GNUNET_OK !=
+        GNUNET_PQ_exec_statements (db,
+                                   db->es)) )
+  {
+    PQfinish (db->conn);
+    db->conn = NULL;
+    return;
+  }
+  if ( (NULL != db->ps) &&
+       (GNUNET_OK !=
+        GNUNET_PQ_prepare_statements (db,
+                                      db->ps)) )
+  {
+    PQfinish (db->conn);
+    db->conn = NULL;
+    return;
+  }
 }
 
 
 /**
  * Connect to a postgres database using the configuration
- * option "CONFIG" in @a section.
+ * option "CONFIG" in @a section.  Also ensures that the
+ * statements in @a es are executed whenever we (re)connect to the
+ * database, and that the prepared statements in @a ps are "ready".
+ *
+ * The caller MUST ensure that @a es and @a ps remain allocated and
+ * initialized in memory until #GNUNET_PQ_disconnect() is called,
+ * as they may be needed repeatedly and no copy will be made.
  *
  * @param cfg configuration
  * @param section configuration section to use to get Postgres configuration 
options
+ * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated
+ *            array of statements to execute upon EACH connection, can be NULL
+ * @param ps array of prepared statements to prepare, can be NULL
  * @return the postgres handle, NULL on error
  */
-PGconn *
+struct GNUNET_PQ_Context *
 GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                            const char *section)
+                            const char *section,
+                            const struct GNUNET_PQ_ExecuteStatement *es,
+                            const struct GNUNET_PQ_PreparedStatement *ps)
 {
-  PGconn *dbh;
+  struct GNUNET_PQ_Context *db;
   char *conninfo;
 
-  /* Open database and precompile statements */
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (cfg,
                                              section,
                                              "CONFIG",
                                              &conninfo))
     conninfo = NULL;
-  dbh = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo);
+  db = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo,
+                          es,
+                          ps);
   GNUNET_free_non_null (conninfo);
-  return dbh;
+  return db;
 }
 
 
+/**
+ * Disconnect from the database, destroying the prepared statements
+ * and releasing other associated resources.
+ *
+ * @param db database handle to disconnect (will be free'd)
+ */
+void
+GNUNET_PQ_disconnect (struct GNUNET_PQ_Context *db)
+{
+  GNUNET_free_non_null (db->es);
+  GNUNET_free_non_null (db->ps);
+  PQfinish (db->conn);
+  GNUNET_free (db);
+}
+
 /* end of pq/pq_connect.c */
diff --git a/src/pq/pq_eval.c b/src/pq/pq_eval.c
index 1d041f226..5bcf8ca0e 100644
--- a/src/pq/pq_eval.c
+++ b/src/pq/pq_eval.c
@@ -1,6 +1,6 @@
 /*
    This file is part of GNUnet
-   Copyright (C) 2017 GNUnet e.V.
+   Copyright (C) 2017, 2019 GNUnet e.V.
 
    GNUnet is free software: you can redistribute it and/or modify it
    under the terms of the GNU Affero General Public License as published
@@ -23,8 +23,7 @@
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_pq_lib.h"
+#include "pq.h"
 
 
 /**
@@ -47,7 +46,7 @@
  * Check the @a result's error code to see what happened.
  * Also logs errors.
  *
- * @param connection connection to execute the statement in
+ * @param db database to execute the statement with
  * @param statement_name name of the statement that created @a result
  * @param result result to check
  * @return status code from the result, mapping PQ status
@@ -57,17 +56,31 @@
  * @deprecated (low level, let's see if we can do with just the high-level 
functions)
  */
 enum GNUNET_DB_QueryStatus
-GNUNET_PQ_eval_result (PGconn *connection,
+GNUNET_PQ_eval_result (struct GNUNET_PQ_Context *db,
                        const char *statement_name,
                        PGresult *result)
 {
   ExecStatusType est;
 
+  if (NULL == result)
+    return GNUNET_DB_STATUS_SOFT_ERROR;
   est = PQresultStatus (result);
   if ((PGRES_COMMAND_OK != est) &&
       (PGRES_TUPLES_OK != est))
   {
     const char *sqlstate;
+    ConnStatusType status;
+
+    if (CONNECTION_OK != (status = PQstatus (db->conn)))
+    {
+      GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
+                       "pq",
+                       "Database connection failed during query `%s': %d 
(reconnecting)\n",
+                       statement_name,
+                       status);
+      GNUNET_PQ_reconnect (db);
+      return GNUNET_DB_STATUS_SOFT_ERROR;
+    }
 
     sqlstate = PQresultErrorField (result,
                                    PG_DIAG_SQLSTATE);
@@ -94,7 +107,7 @@ GNUNET_PQ_eval_result (PGconn *connection,
                                            PG_DIAG_MESSAGE_DETAIL),
                        PQresultErrorMessage (result),
                        PQresStatus (PQresultStatus (result)),
-                       PQerrorMessage (connection));
+                       PQerrorMessage (db->conn));
       return GNUNET_DB_STATUS_SOFT_ERROR;
     }
     if (0 == strcmp (sqlstate,
@@ -111,7 +124,7 @@ GNUNET_PQ_eval_result (PGconn *connection,
                                            PG_DIAG_MESSAGE_DETAIL),
                        PQresultErrorMessage (result),
                        PQresStatus (PQresultStatus (result)),
-                       PQerrorMessage (connection));
+                       PQerrorMessage (db->conn));
       return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
     }
     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
@@ -124,7 +137,7 @@ GNUNET_PQ_eval_result (PGconn *connection,
                                          PG_DIAG_MESSAGE_DETAIL),
                      PQresultErrorMessage (result),
                      PQresStatus (PQresultStatus (result)),
-                     PQerrorMessage (connection));
+                     PQerrorMessage (db->conn));
     return GNUNET_DB_STATUS_HARD_ERROR;
   }
   return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
@@ -136,7 +149,7 @@ GNUNET_PQ_eval_result (PGconn *connection,
  * statement in @a connnection using the given @a params.  Returns the
  * resulting session state.
  *
- * @param connection connection to execute the statement in
+ * @param db database to execute the statement with
  * @param statement_name name of the statement
  * @param params parameters to give to the statement 
(#GNUNET_PQ_query_param_end-terminated)
  * @return status code from the result, mapping PQ status
@@ -148,17 +161,19 @@ GNUNET_PQ_eval_result (PGconn *connection,
  *         zero; if INSERT was successful, we return one.
  */
 enum GNUNET_DB_QueryStatus
-GNUNET_PQ_eval_prepared_non_select (PGconn *connection,
+GNUNET_PQ_eval_prepared_non_select (struct GNUNET_PQ_Context *db,
                                     const char *statement_name,
                                     const struct GNUNET_PQ_QueryParam *params)
 {
   PGresult *result;
   enum GNUNET_DB_QueryStatus qs;
 
-  result = GNUNET_PQ_exec_prepared (connection,
+  result = GNUNET_PQ_exec_prepared (db,
                                     statement_name,
                                     params);
-  qs = GNUNET_PQ_eval_result (connection,
+  if (NULL == result)
+    return GNUNET_DB_STATUS_SOFT_ERROR;
+  qs = GNUNET_PQ_eval_result (db,
                               statement_name,
                               result);
   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
@@ -182,7 +197,7 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection,
  * status including the number of results given to @a rh (possibly zero).
  * @a rh will not have been called if the return value is negative.
  *
- * @param connection connection to execute the statement in
+ * @param db database to execute the statement with
  * @param statement_name name of the statement
  * @param params parameters to give to the statement 
(#GNUNET_PQ_query_param_end-terminated)
  * @param rh function to call with the result set, NULL to ignore
@@ -191,7 +206,7 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection,
  *         codes to `enum GNUNET_DB_QueryStatus`.
  */
 enum GNUNET_DB_QueryStatus
-GNUNET_PQ_eval_prepared_multi_select (PGconn *connection,
+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,
@@ -201,10 +216,12 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection,
   enum GNUNET_DB_QueryStatus qs;
   unsigned int ret;
 
-  result = GNUNET_PQ_exec_prepared (connection,
+  result = GNUNET_PQ_exec_prepared (db,
                                     statement_name,
                                     params);
-  qs = GNUNET_PQ_eval_result (connection,
+  if (NULL == result)
+    return GNUNET_DB_STATUS_SOFT_ERROR;
+  qs = GNUNET_PQ_eval_result (db,
                               statement_name,
                               result);
   if (qs < 0)
@@ -230,7 +247,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection,
  * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT.  Returns the
  * resulting session status.
  *
- * @param connection connection to execute the statement in
+ * @param db database to execute the statement with
  * @param statement_name name of the statement
  * @param params parameters to give to the statement 
(#GNUNET_PQ_query_param_end-terminated)
  * @param[in,out] rs result specification to use for storing the result of the 
query
@@ -238,7 +255,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection,
  *         codes to `enum GNUNET_DB_QueryStatus`.
  */
 enum GNUNET_DB_QueryStatus
-GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection,
+GNUNET_PQ_eval_prepared_singleton_select (struct GNUNET_PQ_Context *db,
                                           const char *statement_name,
                                           const struct
                                           GNUNET_PQ_QueryParam *params,
@@ -247,10 +264,12 @@ GNUNET_PQ_eval_prepared_singleton_select (PGconn 
*connection,
   PGresult *result;
   enum GNUNET_DB_QueryStatus qs;
 
-  result = GNUNET_PQ_exec_prepared (connection,
+  result = GNUNET_PQ_exec_prepared (db,
                                     statement_name,
                                     params);
-  qs = GNUNET_PQ_eval_result (connection,
+  if (NULL == result)
+    return GNUNET_DB_STATUS_SOFT_ERROR;
+  qs = GNUNET_PQ_eval_result (db,
                               statement_name,
                               result);
   if (qs < 0)
diff --git a/src/pq/pq_exec.c b/src/pq/pq_exec.c
index 00527151a..fd4feae53 100644
--- a/src/pq/pq_exec.c
+++ b/src/pq/pq_exec.c
@@ -1,6 +1,6 @@
 /*
    This file is part of GNUnet
-   Copyright (C) 2017 GNUnet e.V.
+   Copyright (C) 2017, 2019 GNUnet e.V.
 
    GNUnet is free software: you can redistribute it and/or modify it
    under the terms of the GNU Affero General Public License as published
@@ -23,8 +23,7 @@
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_pq_lib.h"
+#include "pq.h"
 
 
 /**
@@ -67,14 +66,14 @@ GNUNET_PQ_make_try_execute (const char *sql)
 /**
  * Request execution of an array of statements @a es from Postgres.
  *
- * @param connection connection to execute the statements over
+ * @param db database to execute the statements with
  * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared
  *            statements.
  * @return #GNUNET_OK on success (modulo statements where errors can be 
ignored)
  *         #GNUNET_SYSERR on error
  */
 int
-GNUNET_PQ_exec_statements (PGconn *connection,
+GNUNET_PQ_exec_statements (struct GNUNET_PQ_Context *db,
                            const struct GNUNET_PQ_ExecuteStatement *es)
 {
   for (unsigned int i = 0; NULL != es[i].sql; i++)
@@ -84,8 +83,8 @@ GNUNET_PQ_exec_statements (PGconn *connection,
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Running statement `%s' on %p\n",
                 es[i].sql,
-                connection);
-    result = PQexec (connection,
+                db);
+    result = PQexec (db->conn,
                      es[i].sql);
     if ((GNUNET_NO == es[i].ignore_errors) &&
         (PGRES_COMMAND_OK != PQresultStatus (result)))
@@ -100,7 +99,7 @@ GNUNET_PQ_exec_statements (PGconn *connection,
                                            PG_DIAG_MESSAGE_DETAIL),
                        PQresultErrorMessage (result),
                        PQresStatus (PQresultStatus (result)),
-                       PQerrorMessage (connection));
+                       PQerrorMessage (db->conn));
       PQclear (result);
       return GNUNET_SYSERR;
     }
diff --git a/src/pq/pq_prepare.c b/src/pq/pq_prepare.c
index 0facf100f..b7003fb69 100644
--- a/src/pq/pq_prepare.c
+++ b/src/pq/pq_prepare.c
@@ -1,6 +1,6 @@
 /*
    This file is part of GNUnet
-   Copyright (C) 2017 GNUnet e.V.
+   Copyright (C) 2017, 2019 GNUnet e.V.
 
    GNUnet is free software: you can redistribute it and/or modify it
    under the terms of the GNU Affero General Public License as published
@@ -23,8 +23,7 @@
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_pq_lib.h"
+#include "pq.h"
 
 
 /**
@@ -53,16 +52,42 @@ GNUNET_PQ_make_prepare (const char *name,
 /**
  * Request creation of prepared statements @a ps from Postgres.
  *
- * @param connection connection to prepare the statements for
+ * @param db database to prepare the statements for
  * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared
  *            statements.
  * @return #GNUNET_OK on success,
  *         #GNUNET_SYSERR on error
  */
 int
-GNUNET_PQ_prepare_statements (PGconn *connection,
+GNUNET_PQ_prepare_statements (struct GNUNET_PQ_Context *db,
                               const struct GNUNET_PQ_PreparedStatement *ps)
 {
+  if (db->ps != ps)
+  {
+    /* add 'ps' to list db->ps of prepared statements to run on reconnect! */
+    unsigned int olen = 0; /* length of existing 'db->ps' array */
+    unsigned int nlen = 0; /* length of 'ps' array */
+    struct GNUNET_PQ_PreparedStatement *rps; /* combined array */
+
+    if (NULL != db->ps)
+      while (NULL != db->ps[olen].name)
+        olen++;
+    while (NULL != ps[nlen].name)
+      nlen++;
+    rps = GNUNET_new_array (olen + nlen + 1,
+                            struct GNUNET_PQ_PreparedStatement);
+    if (NULL != db->ps)
+      memcpy (rps,
+              db->ps,
+              olen * sizeof (struct GNUNET_PQ_PreparedStatement));
+    memcpy (&rps[olen],
+            ps,
+            nlen * sizeof (struct GNUNET_PQ_PreparedStatement));
+    GNUNET_free_non_null (db->ps);
+    db->ps = rps;
+  }
+
+  /* actually prepare statements */
   for (unsigned int i = 0; NULL != ps[i].name; i++)
   {
     PGresult *ret;
@@ -72,7 +97,7 @@ GNUNET_PQ_prepare_statements (PGconn *connection,
                      "Preparing SQL statement `%s' as `%s'\n",
                      ps[i].sql,
                      ps[i].name);
-    ret = PQprepare (connection,
+    ret = PQprepare (db->conn,
                      ps[i].name,
                      ps[i].sql,
                      ps[i].num_arguments,
@@ -84,7 +109,7 @@ GNUNET_PQ_prepare_statements (PGconn *connection,
                        _ ("PQprepare (`%s' as `%s') failed with error: %s\n"),
                        ps[i].sql,
                        ps[i].name,
-                       PQerrorMessage (connection));
+                       PQerrorMessage (db->conn));
       PQclear (ret);
       return GNUNET_SYSERR;
     }
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
index cfb16ac12..1fb1e71c0 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -587,7 +587,7 @@ extract_abs_time (void *cls,
   res = (int64_t *) PQgetvalue (result,
                                 row,
                                 fnum);
-  if (INT64_MAX == *res)
+  if (INT64_MAX == GNUNET_ntohll ((uint64_t) *res))
     *udst = GNUNET_TIME_UNIT_FOREVER_ABS;
   else
     udst->abs_value_us = GNUNET_ntohll ((uint64_t) *res);
diff --git a/src/pq/test_pq.c b/src/pq/test_pq.c
index 697d8e580..a103aca5d 100644
--- a/src/pq/test_pq.c
+++ b/src/pq/test_pq.c
@@ -1,6 +1,6 @@
 /*
    This file is part of GNUnet
-   (C) 2015, 2016 GNUnet e.V.
+   (C) 2015, 2016, 2019 GNUnet e.V.
 
    GNUnet is free software: you can redistribute it and/or modify it
    under the terms of the GNU Affero General Public License as published
@@ -23,75 +23,65 @@
  * @author Christian Grothoff <address@hidden>
  */
 #include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_pq_lib.h"
+#include "pq.h"
 
 
 /**
  * Setup prepared statements.
  *
- * @param db_conn connection handle to initialize
+ * @param db database handle to initialize
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
  */
 static int
-postgres_prepare (PGconn *db_conn)
+postgres_prepare (struct GNUNET_PQ_Context *db)
 {
-  PGresult *result;
-
-#define PREPARE(name, sql, ...)                                 \
-  do {                                                          \
-    result = PQprepare (db_conn, name, sql, __VA_ARGS__);       \
-    if (PGRES_COMMAND_OK != PQresultStatus (result))            \
-    {                                                           \
-      GNUNET_break (0);                                         \
-      PQclear (result); result = NULL;                          \
-      return GNUNET_SYSERR;                                     \
-    }                                                           \
-    PQclear (result); result = NULL;                            \
-  } while (0);
+  struct GNUNET_PQ_PreparedStatement ps[] = {
+    GNUNET_PQ_make_prepare ("test_insert",
+                            "INSERT INTO test_pq ("
+                            " pub"
+                            ",sig"
+                            ",abs_time"
+                            ",forever"
+                            ",hash"
+                            ",vsize"
+                            ",u16"
+                            ",u32"
+                            ",u64"
+                            ") VALUES "
+                            "($1, $2, $3, $4, $5, $6,"
+                            "$7, $8, $9);",
+                            9),
+    GNUNET_PQ_make_prepare ("test_select",
+                            "SELECT"
+                            " pub"
+                            ",sig"
+                            ",abs_time"
+                            ",forever"
+                            ",hash"
+                            ",vsize"
+                            ",u16"
+                            ",u32"
+                            ",u64"
+                            " FROM test_pq"
+                            " ORDER BY abs_time DESC "
+                            " LIMIT 1;",
+                            0),
+    GNUNET_PQ_PREPARED_STATEMENT_END
+  };
 
-  PREPARE ("test_insert",
-           "INSERT INTO test_pq ("
-           " pub"
-           ",sig"
-           ",abs_time"
-           ",forever"
-           ",hash"
-           ",vsize"
-           ",u16"
-           ",u32"
-           ",u64"
-           ") VALUES "
-           "($1, $2, $3, $4, $5, $6,"
-           "$7, $8, $9);",
-           9, NULL);
-  PREPARE ("test_select",
-           "SELECT"
-           " pub"
-           ",sig"
-           ",abs_time"
-           ",forever"
-           ",hash"
-           ",vsize"
-           ",u16"
-           ",u32"
-           ",u64"
-           " FROM test_pq"
-           " ORDER BY abs_time DESC "
-           " LIMIT 1;",
-           0, NULL);
-  return GNUNET_OK;
-#undef PREPARE
+  return GNUNET_PQ_prepare_statements (db,
+                                       ps);
 }
 
 
 /**
  * Run actual test queries.
  *
+ * @param db database handle
  * @return 0 on success
  */
 static int
-run_queries (PGconn *conn)
+run_queries (struct GNUNET_PQ_Context *db)
 {
   struct GNUNET_CRYPTO_RsaPublicKey *pub;
   struct GNUNET_CRYPTO_RsaPublicKey *pub2 = NULL;
@@ -155,7 +145,7 @@ run_queries (PGconn *conn)
       GNUNET_PQ_result_spec_end
     };
 
-    result = GNUNET_PQ_exec_prepared (conn,
+    result = GNUNET_PQ_exec_prepared (db,
                                       "test_insert",
                                       params_insert);
     if (PGRES_COMMAND_OK != PQresultStatus (result))
@@ -171,7 +161,7 @@ run_queries (PGconn *conn)
     }
 
     PQclear (result);
-    result = GNUNET_PQ_exec_prepared (conn,
+    result = GNUNET_PQ_exec_prepared (db,
                                       "test_select",
                                       params_select);
     if (1 !=
@@ -224,67 +214,71 @@ int
 main (int argc,
       const char *const argv[])
 {
-  PGconn *conn;
-  PGresult *result;
+  struct GNUNET_PQ_ExecuteStatement es[] = {
+    GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq ("
+                            " pub BYTEA NOT NULL"
+                            ",sig BYTEA NOT NULL"
+                            ",abs_time INT8 NOT NULL"
+                            ",forever INT8 NOT NULL"
+                            ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)"
+                            ",vsize VARCHAR NOT NULL"
+                            ",u16 INT2 NOT NULL"
+                            ",u32 INT4 NOT NULL"
+                            ",u64 INT8 NOT NULL"
+                            ")"),
+    GNUNET_PQ_EXECUTE_STATEMENT_END
+  };
+  struct GNUNET_PQ_Context *db;
   int ret;
 
   GNUNET_log_setup ("test-pq",
                     "WARNING",
                     NULL);
-  conn = PQconnectdb ("postgres:///gnunetcheck");
-  if (CONNECTION_OK != PQstatus (conn))
+  db = GNUNET_PQ_connect ("postgres:///gnunetcheck",
+                          es,
+                          NULL);
+  if (CONNECTION_OK != PQstatus (db->conn))
   {
     fprintf (stderr,
              "Cannot run test, database connection failed: %s\n",
-             PQerrorMessage (conn));
+             PQerrorMessage (db->conn));
     GNUNET_break (0);
-    PQfinish (conn);
+    GNUNET_PQ_disconnect (db);
     return 77;   /* signal test was skipped */
   }
-
-  result = PQexec (conn,
-                   "CREATE TEMPORARY TABLE IF NOT EXISTS test_pq ("
-                   " pub BYTEA NOT NULL"
-                   ",sig BYTEA NOT NULL"
-                   ",abs_time INT8 NOT NULL"
-                   ",forever INT8 NOT NULL"
-                   ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)"
-                   ",vsize VARCHAR NOT NULL"
-                   ",u16 INT2 NOT NULL"
-                   ",u32 INT4 NOT NULL"
-                   ",u64 INT8 NOT NULL"
-                   ")");
-  if (PGRES_COMMAND_OK != PQresultStatus (result))
-  {
-    fprintf (stderr,
-             "Failed to create table: %s\n",
-             PQerrorMessage (conn));
-    PQclear (result);
-    PQfinish (conn);
-    return 1;
-  }
-  PQclear (result);
   if (GNUNET_OK !=
-      postgres_prepare (conn))
+      postgres_prepare (db))
   {
     GNUNET_break (0);
-    PQfinish (conn);
+    GNUNET_PQ_disconnect (db);
     return 1;
   }
-  ret = run_queries (conn);
-  result = PQexec (conn,
-                   "DROP TABLE test_pq");
-  if (PGRES_COMMAND_OK != PQresultStatus (result))
+  ret = run_queries (db);
+#if TEST_RESTART
+  fprintf (stderr, "Please restart Postgres database now!\n");
+  sleep (60);
+  ret = run_queries (db);
+  fprintf (stderr, "Result: %d (expect: 1 -- if you restarted the DB)\n", ret);
+  ret = run_queries (db);
+  fprintf (stderr, "Result: %d (expect: 0)\n", ret);
+#endif
   {
-    fprintf (stderr,
-             "Failed to create table: %s\n",
-             PQerrorMessage (conn));
-    PQclear (result);
-    PQfinish (conn);
-    return 1;
+    struct GNUNET_PQ_ExecuteStatement es[] = {
+      GNUNET_PQ_make_execute ("DROP TABLE test_pq"),
+      GNUNET_PQ_EXECUTE_STATEMENT_END
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_exec_statements (db,
+                                   es))
+    {
+      fprintf (stderr,
+               "Failed to drop table\n");
+      GNUNET_PQ_disconnect (db);
+      return 1;
+    }
   }
-  PQclear (result);
-  PQfinish (conn);
+  GNUNET_PQ_disconnect (db);
   return ret;
 }
 

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]