gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] branch master updated (0ea0684f -> 6cf8a87b)


From: gnunet
Subject: [taler-merchant] branch master updated (0ea0684f -> 6cf8a87b)
Date: Tue, 09 May 2023 18:05:13 +0200

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

ivan-avalos pushed a change to branch master
in repository merchant.

    from 0ea0684f -fix transfer tracking test
     new 1b39e3bc Factor out lookup_instance_auth (shit job)
     new c3a28e71 Factor out insert_instance (shit job)
     new dec32b9a Factor out account_kyc_set_status (shit job)
     new 41719f3d Factor out account_kyc_get_status (shit job)
     new 90421ed0 Factor out delete_instance_private_key (shit job)
     new 8d4ec086 Factor out purge_instance and update_instance (shit job)
     new 2bdf34b5 Factor out update_instance_auth (shit_job)
     new 7b900027 Factor out inactivate_account (shit job)
     new 75c1fbfe Factor out activate_account (shit job)
     new 6cf8a87b Factor out {lookup,delete,insert,update,lock}_product(s) 
(shit job)

The 10 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/backenddb/Makefile.am                          |   16 +
 src/backenddb/pg_account_kyc_get_status.c          |  194 ++++
 ...nsert_account.h => pg_account_kyc_get_status.h} |   30 +-
 src/backenddb/pg_account_kyc_set_status.c          |   88 ++
 src/backenddb/pg_account_kyc_set_status.h          |   55 +
 ..._wirewatch_progress.c => pg_activate_account.c} |   36 +-
 .../{pg_insert_account.h => pg_activate_account.h} |   24 +-
 ...accounts.c => pg_delete_instance_private_key.c} |   26 +-
 ..._account.h => pg_delete_instance_private_key.h} |   20 +-
 ...ete_exchange_accounts.c => pg_delete_product.c} |   35 +-
 .../{pg_insert_account.h => pg_delete_product.h}   |   28 +-
 ...irewatch_progress.c => pg_inactivate_account.c} |   38 +-
 ...pg_insert_account.h => pg_inactivate_account.h} |   23 +-
 src/backenddb/pg_insert_instance.c                 |  111 ++
 .../{pg_insert_account.h => pg_insert_instance.h}  |   28 +-
 src/backenddb/pg_insert_product.c                  |   76 ++
 .../{pg_insert_account.h => pg_insert_product.h}   |   26 +-
 src/backenddb/pg_lock_product.c                    |   76 ++
 src/backenddb/pg_lock_product.h                    |   49 +
 src/backenddb/pg_lookup_instance_auth.c            |   59 +
 ...change_accounts.h => pg_lookup_instance_auth.h} |   24 +-
 src/backenddb/pg_lookup_product.c                  |  110 ++
 .../{pg_insert_account.h => pg_lookup_product.h}   |   27 +-
 src/backenddb/pg_lookup_products.c                 |  126 +++
 ...t_wirewatch_accounts.h => pg_lookup_products.h} |   27 +-
 ...ete_exchange_accounts.c => pg_purge_instance.c} |   32 +-
 .../{pg_insert_account.h => pg_purge_instance.h}   |   21 +-
 src/backenddb/pg_update_instance.c                 |   80 ++
 .../{pg_insert_account.h => pg_update_instance.h}  |   22 +-
 ...change_accounts.c => pg_update_instance_auth.c} |   28 +-
 ..._insert_account.h => pg_update_instance_auth.h} |   25 +-
 src/backenddb/pg_update_product.c                  |   85 ++
 src/backenddb/pg_update_product.h                  |   53 +
 src/backenddb/plugin_merchantdb_postgres.c         | 1147 +-------------------
 34 files changed, 1488 insertions(+), 1357 deletions(-)
 create mode 100644 src/backenddb/pg_account_kyc_get_status.c
 copy src/backenddb/{pg_insert_account.h => pg_account_kyc_get_status.h} (50%)
 create mode 100644 src/backenddb/pg_account_kyc_set_status.c
 create mode 100644 src/backenddb/pg_account_kyc_set_status.h
 copy src/backenddb/{pg_update_wirewatch_progress.c => pg_activate_account.c} 
(63%)
 copy src/backenddb/{pg_insert_account.h => pg_activate_account.h} (63%)
 copy src/backenddb/{pg_delete_exchange_accounts.c => 
pg_delete_instance_private_key.c} (64%)
 copy src/backenddb/{pg_insert_account.h => pg_delete_instance_private_key.h} 
(67%)
 copy src/backenddb/{pg_delete_exchange_accounts.c => pg_delete_product.c} (53%)
 copy src/backenddb/{pg_insert_account.h => pg_delete_product.h} (57%)
 copy src/backenddb/{pg_update_wirewatch_progress.c => pg_inactivate_account.c} 
(62%)
 copy src/backenddb/{pg_insert_account.h => pg_inactivate_account.h} (62%)
 create mode 100644 src/backenddb/pg_insert_instance.c
 copy src/backenddb/{pg_insert_account.h => pg_insert_instance.h} (53%)
 create mode 100644 src/backenddb/pg_insert_product.c
 copy src/backenddb/{pg_insert_account.h => pg_insert_product.h} (60%)
 create mode 100644 src/backenddb/pg_lock_product.c
 create mode 100644 src/backenddb/pg_lock_product.h
 create mode 100644 src/backenddb/pg_lookup_instance_auth.c
 copy src/backenddb/{pg_delete_exchange_accounts.h => 
pg_lookup_instance_auth.h} (62%)
 create mode 100644 src/backenddb/pg_lookup_product.c
 copy src/backenddb/{pg_insert_account.h => pg_lookup_product.h} (57%)
 create mode 100644 src/backenddb/pg_lookup_products.c
 copy src/backenddb/{pg_select_wirewatch_accounts.h => pg_lookup_products.h} 
(61%)
 copy src/backenddb/{pg_delete_exchange_accounts.c => pg_purge_instance.c} (60%)
 copy src/backenddb/{pg_insert_account.h => pg_purge_instance.h} (68%)
 create mode 100644 src/backenddb/pg_update_instance.c
 copy src/backenddb/{pg_insert_account.h => pg_update_instance.h} (65%)
 copy src/backenddb/{pg_delete_exchange_accounts.c => 
pg_update_instance_auth.c} (62%)
 copy src/backenddb/{pg_insert_account.h => pg_update_instance_auth.h} (60%)
 create mode 100644 src/backenddb/pg_update_product.c
 create mode 100644 src/backenddb/pg_update_product.h

diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index ab46a59e..91b48223 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -65,6 +65,22 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \
   pg_set_transfer_status_to_confirmed.h pg_set_transfer_status_to_confirmed.c \
   pg_insert_exchange_account.h pg_insert_exchange_account.c \
   pg_lookup_reserves.h pg_lookup_reserves.c \
+  pg_lookup_instance_auth.h pg_lookup_instance_auth.c \
+  pg_insert_instance.h pg_insert_instance.c \
+  pg_account_kyc_set_status.h pg_account_kyc_set_status.c \
+  pg_account_kyc_get_status.h pg_account_kyc_get_status.c \
+  pg_delete_instance_private_key.h pg_delete_instance_private_key.c \
+  pg_purge_instance.h pg_purge_instance.c \
+  pg_update_instance.h pg_update_instance.c \
+  pg_update_instance_auth.h pg_update_instance_auth.c \
+  pg_inactivate_account.h pg_inactivate_account.c \
+  pg_activate_account.h pg_activate_account.c \
+  pg_lookup_products.h pg_lookup_products.c \
+  pg_lookup_product.h pg_lookup_product.c \
+  pg_delete_product.h pg_delete_product.c \
+  pg_insert_product.h pg_insert_product.c \
+  pg_update_product.h pg_update_product.c \
+  pg_lock_product.h pg_lock_product.c \
   plugin_merchantdb_postgres.c  pg_helper.h
 libtaler_plugin_merchantdb_postgres_la_LIBADD = \
   $(LTLIBINTL)
diff --git a/src/backenddb/pg_account_kyc_get_status.c 
b/src/backenddb/pg_account_kyc_get_status.c
new file mode 100644
index 00000000..8fd79945
--- /dev/null
+++ b/src/backenddb/pg_account_kyc_get_status.c
@@ -0,0 +1,194 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_account_kyc_get_status.c
+ * @brief Implementation of the account_kyc_get_status function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_account_kyc_get_status.h"
+#include "pg_helper.h"
+
+/**
+ * Closure for kyc_status_cb().
+ */
+struct KycStatusContext
+{
+  /**
+   * Function to call with results.
+   */
+  TALER_MERCHANTDB_KycCallback kyc_cb;
+
+  /**
+   * Closure for @e kyc_cb.
+   */
+  void *kyc_cb_cls;
+
+  /**
+   * Filter, NULL to not filter.
+   */
+  const struct TALER_MerchantWireHashP *h_wire;
+
+  /**
+   * Filter, NULL to not filter.
+   */
+  const char *exchange_url;
+
+  /**
+   * Number of results found.
+   */
+  unsigned int count;
+
+  /**
+   * Set to true on failure(s).
+   */
+  bool failure;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results about accounts.
+ *
+ * @param[in,out] cls of type `struct KycStatusContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+kyc_status_cb (void *cls,
+               PGresult *result,
+               unsigned int num_results)
+{
+  struct KycStatusContext *ksc = cls;
+
+  for (unsigned int i = 0; i < num_results; i++)
+  {
+    struct TALER_MerchantWireHashP h_wire;
+    uint64_t kyc_serial;
+    char *exchange_url;
+    char *payto_uri;
+    struct GNUNET_TIME_Timestamp last_check;
+    bool kyc_ok;
+    uint32_t aml_decision;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_auto_from_type ("h_wire",
+                                            &h_wire),
+      GNUNET_PQ_result_spec_uint64 ("exchange_kyc_serial",
+                                    &kyc_serial),
+      GNUNET_PQ_result_spec_string ("payto_uri",
+                                    &payto_uri),
+      GNUNET_PQ_result_spec_string ("exchange_url",
+                                    &exchange_url),
+      GNUNET_PQ_result_spec_timestamp ("kyc_timestamp",
+                                       &last_check),
+      GNUNET_PQ_result_spec_bool ("kyc_ok",
+                                  &kyc_ok),
+      GNUNET_PQ_result_spec_uint32 ("aml_decision",
+                                    &aml_decision),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ksc->failure = true;
+      return;
+    }
+    if ( (NULL != ksc->exchange_url) &&
+         (0 != strcmp (ksc->exchange_url,
+                       exchange_url)) )
+    {
+      GNUNET_PQ_cleanup_result (rs);
+      continue;
+    }
+    if ( (NULL != ksc->h_wire) &&
+         (0 != GNUNET_memcmp (ksc->h_wire,
+                              &h_wire)) )
+    {
+      GNUNET_PQ_cleanup_result (rs);
+      continue;
+    }
+    ksc->count++;
+    ksc->kyc_cb (ksc->kyc_cb_cls,
+                 &h_wire,
+                 kyc_serial,
+                 payto_uri,
+                 exchange_url,
+                 last_check,
+                 kyc_ok,
+                 (enum TALER_AmlDecisionState) aml_decision);
+    GNUNET_PQ_cleanup_result (rs);
+  }
+}
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_account_kyc_get_status (void *cls,
+                               const char *merchant_id,
+                               const struct TALER_MerchantWireHashP *h_wire,
+                               const char *exchange_url,
+                               TALER_MERCHANTDB_KycCallback kyc_cb,
+                               void *kyc_cb_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct KycStatusContext ksc = {
+    .kyc_cb = kyc_cb,
+    .kyc_cb_cls = kyc_cb_cls,
+    .exchange_url = exchange_url,
+    .h_wire = h_wire
+  };
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (merchant_id),
+    GNUNET_PQ_query_param_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  check_connection (pg);
+  PREPARE (pg,
+           "lookup_kyc_status",
+           "SELECT"
+           " h_wire"
+           ",exchange_kyc_serial"
+           ",payto_uri"
+           ",exchange_url"
+           ",kyc_timestamp"
+           ",kyc_ok"
+           ",aml_decision"
+           " FROM merchant_instances"
+           " JOIN merchant_accounts"
+           "   USING (merchant_serial)"
+           " JOIN merchant_kyc"
+           "   USING (account_serial)"
+           " WHERE merchant_instances.merchant_id=$1");
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                             "lookup_kyc_status",
+                                             params,
+                                             &kyc_status_cb,
+                                             &ksc);
+  if (ksc.failure)
+  {
+    GNUNET_break (0);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+  if (0 > qs)
+    return qs;
+  return ksc.count;
+}
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_account_kyc_get_status.h
similarity index 50%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_account_kyc_get_status.h
index 463bc527..41d5c05d 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_account_kyc_get_status.h
@@ -14,30 +14,36 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
+ * @file backenddb/pg_account_kyc_get_status.h
+ * @brief implementation of the account_kyc_get_status function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_ACCOUNT_KYC_GET_STATUS_H
+#define PG_ACCOUNT_KYC_GET_STATUS_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Check an instance's account's KYC status.
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
+ * @param merchant_id merchant backend instance ID
+ * @param h_wire hash of the wire account to check,
+ *        NULL to check all accounts of the merchant
+ * @param exchange_url base URL of the exchange to check,
+ *        NULL to check all exchanges
+ * @param kyc_cb KYC status callback to invoke
+ * @param kyc_cb_cls closure for @a kyc_cb
  * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
-
+TMH_PG_account_kyc_get_status (void *cls,
+                               const char *merchant_id,
+                               const struct TALER_MerchantWireHashP *h_wire,
+                               const char *exchange_url,
+                               TALER_MERCHANTDB_KycCallback kyc_cb,
+                               void *kyc_cb_cls);
 
 #endif
diff --git a/src/backenddb/pg_account_kyc_set_status.c 
b/src/backenddb/pg_account_kyc_set_status.c
new file mode 100644
index 00000000..6c69c448
--- /dev/null
+++ b/src/backenddb/pg_account_kyc_set_status.c
@@ -0,0 +1,88 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_account_kyc_set_status.c
+ * @brief Implementation of the account_kyc_set_status function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_account_kyc_set_status.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_account_kyc_set_status (
+  void *cls,
+  const char *merchant_id,
+  const struct TALER_MerchantWireHashP *h_wire,
+  const char *exchange_url,
+  uint64_t exchange_kyc_serial,
+  const struct TALER_ExchangeSignatureP *exchange_sig,
+  const struct TALER_ExchangePublicKeyP *exchange_pub,
+  struct GNUNET_TIME_Timestamp timestamp,
+  bool kyc_ok,
+  enum TALER_AmlDecisionState aml_decision)
+{
+  struct PostgresClosure *pg = cls;
+  uint32_t aml32 = (uint32_t) aml_decision;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (merchant_id),
+    GNUNET_PQ_query_param_auto_from_type (h_wire),
+    GNUNET_PQ_query_param_string (exchange_url),
+    GNUNET_PQ_query_param_uint64 (&exchange_kyc_serial),
+    GNUNET_PQ_query_param_timestamp (&timestamp),
+    GNUNET_PQ_query_param_bool (kyc_ok),
+    exchange_pub
+    ? GNUNET_PQ_query_param_auto_from_type (exchange_pub)
+    : GNUNET_PQ_query_param_null (),
+    exchange_sig
+    ? GNUNET_PQ_query_param_auto_from_type (exchange_sig)
+    : GNUNET_PQ_query_param_null (),
+    GNUNET_PQ_query_param_uint32 (&aml32),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "upsert_account_kyc",
+           "INSERT INTO merchant_kyc"
+           "(kyc_timestamp"
+           ",kyc_ok"
+           ",exchange_kyc_serial"
+           ",account_serial"
+           ",exchange_url"
+           ",exchange_pub"
+           ",exchange_sig"
+           ",aml_decision)"
+           " SELECT $5, $6, $4, account_serial, $3, $7, $8, $9"
+           " FROM merchant_instances"
+           " JOIN merchant_accounts USING (merchant_serial)"
+           " WHERE merchant_id=$1"
+           "  AND h_wire=$2"
+           " ON CONFLICT(account_serial,exchange_url) DO "
+           "UPDATE"
+           " SET exchange_kyc_serial=$4"
+           "    ,kyc_timestamp=$5"
+           "    ,kyc_ok=$6"
+           "    ,exchange_pub=$7"
+           "    ,exchange_sig=$8"
+           "    ,aml_decision=$9");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "upsert_account_kyc",
+                                             params);
+}
diff --git a/src/backenddb/pg_account_kyc_set_status.h 
b/src/backenddb/pg_account_kyc_set_status.h
new file mode 100644
index 00000000..f8a8d96b
--- /dev/null
+++ b/src/backenddb/pg_account_kyc_set_status.h
@@ -0,0 +1,55 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_account_kyc_set_status.h
+ * @brief implementation of the account_kyc_set_status function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_ACCOUNT_KYC_SET_STATUS_H
+#define PG_ACCOUNT_KYC_SET_STATUS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Update an instance's account's KYC status.
+ *
+ * @param cls closure
+ * @param merchant_id merchant backend instance ID
+ * @param h_wire hash of the wire account to check
+ * @param exchange_url base URL of the exchange to check
+ * @param exchange_kyc_serial serial number for our account at the exchange (0 
if unknown)
+ * @param exchange_sig signature of the exchange, or NULL for none
+ * @param exchange_pub public key of the exchange, or NULL for none
+ * @param timestamp timestamp to store
+ * @param kyc_ok current KYC status (true for satisfied)
+ * @param aml_decision current AML decision state at the exchange
+ * @return database result code
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_account_kyc_set_status (void *cls,
+                               const char *merchant_id,
+                               const struct TALER_MerchantWireHashP *h_wire,
+                               const char *exchange_url,
+                               uint64_t exchange_kyc_serial,
+                               const struct TALER_ExchangeSignatureP 
*exchange_sig,
+                               const struct TALER_ExchangePublicKeyP 
*exchange_pub,
+                               struct GNUNET_TIME_Timestamp timestamp,
+                               bool kyc_ok,
+                               enum TALER_AmlDecisionState aml_decision);
+
+#endif
diff --git a/src/backenddb/pg_update_wirewatch_progress.c 
b/src/backenddb/pg_activate_account.c
similarity index 63%
copy from src/backenddb/pg_update_wirewatch_progress.c
copy to src/backenddb/pg_activate_account.c
index 8ffdfe70..21c23752 100644
--- a/src/backenddb/pg_update_wirewatch_progress.c
+++ b/src/backenddb/pg_activate_account.c
@@ -14,44 +14,40 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_update_wirewatch_progress.c
- * @brief Implementation of the update_wirewatch_progress function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_activate_account.c
+ * @brief Implementation of the activate_account function for Postgres
+ * @author Iván Ávalos
  */
 #include "platform.h"
 #include <taler/taler_error_codes.h>
 #include <taler/taler_dbevents.h>
 #include <taler/taler_pq_lib.h>
-#include "pg_update_wirewatch_progress.h"
+#include "pg_activate_account.h"
 #include "pg_helper.h"
 
-
 enum GNUNET_DB_QueryStatus
-TMH_PG_update_wirewatch_progress (
-  void *cls,
-  const char *instance,
-  const char *payto_uri,
-  uint64_t last_serial)
+TMH_PG_activate_account (void *cls,
+                         const char *merchant_id,
+                         const struct TALER_MerchantWireHashP *h_wire)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance),
-    GNUNET_PQ_query_param_string (payto_uri),
-    GNUNET_PQ_query_param_uint64 (&last_serial),
+    GNUNET_PQ_query_param_string (merchant_id),
+    GNUNET_PQ_query_param_auto_from_type (h_wire),
     GNUNET_PQ_query_param_end
   };
 
+  check_connection (pg);
   PREPARE (pg,
-           "update_wirewatch_progress",
-           "UPDATE merchant_accounts"
-           " SET last_bank_serial=$3"
-           " WHERE payto_uri=$2"
-           "  AND merchant_serial ="
+           "activate_account",
+           "UPDATE merchant_accounts SET"
+           " active=TRUE"
+           " WHERE h_wire=$2 AND"
+           " merchant_serial="
            "   (SELECT merchant_serial"
            "      FROM merchant_instances"
            "      WHERE merchant_id=$1)");
-  check_connection (pg);
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "update_wirewatch_progress",
+                                             "activate_account",
                                              params);
 }
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_activate_account.h
similarity index 63%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_activate_account.h
index 463bc527..5edb7d1a 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_activate_account.h
@@ -14,30 +14,28 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_activate_account.h
+ * @brief implementation of the activate_account function for Postgres
+ * @author Iván Ávalos
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_ACTIVATE_ACCOUNT_H
+#define PG_ACTIVATE_ACCOUNT_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Set an instance's account in our database to "active".
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
+ * @param merchant_id merchant backend instance ID
+ * @param h_wire hash of the wire account to set to active
  * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
-
+TMH_PG_activate_account (void *cls,
+                         const char *merchant_id,
+                         const struct TALER_MerchantWireHashP *h_wire);
 
 #endif
diff --git a/src/backenddb/pg_delete_exchange_accounts.c 
b/src/backenddb/pg_delete_instance_private_key.c
similarity index 64%
copy from src/backenddb/pg_delete_exchange_accounts.c
copy to src/backenddb/pg_delete_instance_private_key.c
index 7d8a5e48..5c7356ad 100644
--- a/src/backenddb/pg_delete_exchange_accounts.c
+++ b/src/backenddb/pg_delete_instance_private_key.c
@@ -14,35 +14,37 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_delete_exchange_accounts.c
- * @brief Implementation of the delete_exchange_accounts function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_delete_instance_private_key.c
+ * @brief Implementation of the delete_instance_private_key function for 
Postgres
+ * @author Iván Ávalos
  */
 #include "platform.h"
 #include <taler/taler_error_codes.h>
 #include <taler/taler_dbevents.h>
 #include <taler/taler_pq_lib.h>
-#include "pg_delete_exchange_accounts.h"
+#include "pg_delete_instance_private_key.h"
 #include "pg_helper.h"
 
-
 enum GNUNET_DB_QueryStatus
-TMH_PG_delete_exchange_accounts (
+TMH_PG_delete_instance_private_key (
   void *cls,
-  const struct TALER_MasterPublicKeyP *master_pub)
+  const char *merchant_id)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (master_pub),
+    GNUNET_PQ_query_param_string (merchant_id),
     GNUNET_PQ_query_param_end
   };
 
   check_connection (pg);
   PREPARE (pg,
-           "delete_exchange_accounts",
-           "DELETE FROM merchant_exchange_accounts"
-           " WHERE master_pub=$1;");
+           "delete_key",
+           "DELETE FROM merchant_keys"
+           " USING merchant_instances"
+           " WHERE merchant_keys.merchant_serial"
+           "   = merchant_instances.merchant_serial"
+           " AND merchant_instances.merchant_id = $1");
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "delete_exchange_accounts",
+                                             "delete_key",
                                              params);
 }
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_delete_instance_private_key.h
similarity index 67%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_delete_instance_private_key.h
index 463bc527..9a8b3be6 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_delete_instance_private_key.h
@@ -14,30 +14,26 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
+ * @file backenddb/pg_delete_instance_private_key.h
+ * @brief implementation of the delete_instance_private_key function for 
Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_DELETE_INSTANCE_PRIVATE_KEY_H
+#define PG_DELETE_INSTANCE_PRIVATE_KEY_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Delete private key of an instance from our database.
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
+ * @param merchant_id identifier of the instance
  * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
-
+TMH_PG_delete_instance_private_key (void *cls,
+                                    const char *merchant_id);
 
 #endif
diff --git a/src/backenddb/pg_delete_exchange_accounts.c 
b/src/backenddb/pg_delete_product.c
similarity index 53%
copy from src/backenddb/pg_delete_exchange_accounts.c
copy to src/backenddb/pg_delete_product.c
index 7d8a5e48..2d70c9b8 100644
--- a/src/backenddb/pg_delete_exchange_accounts.c
+++ b/src/backenddb/pg_delete_product.c
@@ -14,35 +14,44 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_delete_exchange_accounts.c
- * @brief Implementation of the delete_exchange_accounts function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_delete_product.c
+ * @brief Implementation of the delete_product function for Postgres
+ * @author Iván Ávalos
  */
 #include "platform.h"
 #include <taler/taler_error_codes.h>
 #include <taler/taler_dbevents.h>
 #include <taler/taler_pq_lib.h>
-#include "pg_delete_exchange_accounts.h"
+#include "pg_delete_product.h"
 #include "pg_helper.h"
 
-
 enum GNUNET_DB_QueryStatus
-TMH_PG_delete_exchange_accounts (
-  void *cls,
-  const struct TALER_MasterPublicKeyP *master_pub)
+TMH_PG_delete_product (void *cls,
+                       const char *instance_id,
+                       const char *product_id)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (master_pub),
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (product_id),
     GNUNET_PQ_query_param_end
   };
 
   check_connection (pg);
   PREPARE (pg,
-           "delete_exchange_accounts",
-           "DELETE FROM merchant_exchange_accounts"
-           " WHERE master_pub=$1;");
+           "delete_product",
+           "DELETE"
+           " FROM merchant_inventory"
+           " WHERE merchant_inventory.merchant_serial="
+           "     (SELECT merchant_serial "
+           "        FROM merchant_instances"
+           "        WHERE merchant_id=$1)"
+           "   AND merchant_inventory.product_id=$2"
+           "   AND product_serial NOT IN "
+           "     (SELECT product_serial FROM merchant_order_locks)"
+           "   AND product_serial NOT IN "
+           "     (SELECT product_serial FROM merchant_inventory_locks)");
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "delete_exchange_accounts",
+                                             "delete_product",
                                              params);
 }
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_delete_product.h
similarity index 57%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_delete_product.h
index 463bc527..c88e46f4 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_delete_product.h
@@ -14,30 +14,30 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_delete_product.h
+ * @brief implementation of the delete_product function for Postgres
+ * @author Iván Ávalos
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_DELETE_PRODUCT_H
+#define PG_DELETE_PRODUCT_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Delete information about a product.  Note that the transaction must
+ * enforce that no stocks are currently locked.
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
- * @return database result code
+ * @param instance_id instance to delete product of
+ * @param product_id product to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ *           if locks prevent deletion OR product unknown
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
-
+TMH_PG_delete_product (void *cls,
+                       const char *instance_id,
+                       const char *product_id);
 
 #endif
diff --git a/src/backenddb/pg_update_wirewatch_progress.c 
b/src/backenddb/pg_inactivate_account.c
similarity index 62%
copy from src/backenddb/pg_update_wirewatch_progress.c
copy to src/backenddb/pg_inactivate_account.c
index 8ffdfe70..67c39462 100644
--- a/src/backenddb/pg_update_wirewatch_progress.c
+++ b/src/backenddb/pg_inactivate_account.c
@@ -14,44 +14,42 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_update_wirewatch_progress.c
- * @brief Implementation of the update_wirewatch_progress function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_inactivate_account.c
+ * @brief Implementation of the inactivate_account function for Postgres
+ * @author Iván Ávalos
  */
 #include "platform.h"
 #include <taler/taler_error_codes.h>
 #include <taler/taler_dbevents.h>
 #include <taler/taler_pq_lib.h>
-#include "pg_update_wirewatch_progress.h"
+#include "pg_inactivate_account.h"
 #include "pg_helper.h"
 
-
 enum GNUNET_DB_QueryStatus
-TMH_PG_update_wirewatch_progress (
-  void *cls,
-  const char *instance,
-  const char *payto_uri,
-  uint64_t last_serial)
+TMH_PG_inactivate_account (void *cls,
+                           const char *merchant_id,
+                           const struct TALER_MerchantWireHashP *h_wire)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance),
-    GNUNET_PQ_query_param_string (payto_uri),
-    GNUNET_PQ_query_param_uint64 (&last_serial),
+    GNUNET_PQ_query_param_string (merchant_id),
+    GNUNET_PQ_query_param_auto_from_type (h_wire),
     GNUNET_PQ_query_param_end
   };
 
+  check_connection (pg);
+  /* the merchant instance is implied from the random salt
+     that is part of the h_wire calculation */
   PREPARE (pg,
-           "update_wirewatch_progress",
-           "UPDATE merchant_accounts"
-           " SET last_bank_serial=$3"
-           " WHERE payto_uri=$2"
-           "  AND merchant_serial ="
+           "inactivate_account",
+           "UPDATE merchant_accounts SET"
+           " active=FALSE"
+           " WHERE h_wire=$2"
+           "  AND merchant_serial="
            "   (SELECT merchant_serial"
            "      FROM merchant_instances"
            "      WHERE merchant_id=$1)");
-  check_connection (pg);
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "update_wirewatch_progress",
+                                             "inactivate_account",
                                              params);
 }
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_inactivate_account.h
similarity index 62%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_inactivate_account.h
index 463bc527..5146faca 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_inactivate_account.h
@@ -14,30 +14,29 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_inactivate_account.h
+ * @brief implementation of the inactivate_account function for Postgres
+ * @author Iván Ávalos
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_INACTIVATE_ACCOUNT_H
+#define PG_INACTIVATE_ACCOUNT_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Set an instance's account in our database to "inactive".
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
+ * @param merchant_id merchant backend instance ID
+ * @param h_wire hash of the wire account to set to inactive
  * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
+TMH_PG_inactivate_account (void *cls,
+                           const char *merchant_id,
+                           const struct TALER_MerchantWireHashP *h_wire);
 
 
 #endif
diff --git a/src/backenddb/pg_insert_instance.c 
b/src/backenddb/pg_insert_instance.c
new file mode 100644
index 00000000..3777f743
--- /dev/null
+++ b/src/backenddb/pg_insert_instance.c
@@ -0,0 +1,111 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_instance.c
+ * @brief Implementation of the insert_instance function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_instance.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_instance (
+  void *cls,
+  const struct TALER_MerchantPublicKeyP *merchant_pub,
+  const struct TALER_MerchantPrivateKeyP *merchant_priv,
+  const struct TALER_MERCHANTDB_InstanceSettings *is,
+  const struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
+{
+  struct PostgresClosure *pg = cls;
+  uint32_t ut32 = (uint32_t) is->ut;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+    GNUNET_PQ_query_param_auto_from_type (&ias->auth_hash),
+    GNUNET_PQ_query_param_auto_from_type (&ias->auth_salt),
+    GNUNET_PQ_query_param_string (is->id),
+    GNUNET_PQ_query_param_string (is->name),
+    GNUNET_PQ_query_param_uint32 (&ut32),
+    TALER_PQ_query_param_json (is->address),
+    TALER_PQ_query_param_json (is->jurisdiction),
+    TALER_PQ_query_param_amount (&is->default_max_deposit_fee),
+    TALER_PQ_query_param_amount (&is->default_max_wire_fee),
+    GNUNET_PQ_query_param_uint32 (&is->default_wire_fee_amortization),
+    GNUNET_PQ_query_param_relative_time (
+      &is->default_wire_transfer_delay),
+    GNUNET_PQ_query_param_relative_time (&is->default_pay_delay),
+    (NULL == is->website)
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_string (is->website),
+    (NULL == is->email)
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_string (is->email),
+    (NULL == is->logo)
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_string (is->logo),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_QueryParam params_priv[] = {
+    GNUNET_PQ_query_param_auto_from_type (merchant_priv),
+    GNUNET_PQ_query_param_string (is->id),
+    GNUNET_PQ_query_param_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  check_connection (pg);
+  PREPARE (pg,
+           "insert_instance",
+           "INSERT INTO merchant_instances"
+           "(merchant_pub"
+           ",auth_hash"
+           ",auth_salt"
+           ",merchant_id"
+           ",merchant_name"
+           ",user_type"
+           ",address"
+           ",jurisdiction"
+           ",default_max_deposit_fee_val"
+           ",default_max_deposit_fee_frac"
+           ",default_max_wire_fee_val"
+           ",default_max_wire_fee_frac"
+           ",default_wire_fee_amortization"
+           ",default_wire_transfer_delay"
+           ",default_pay_delay"
+           ",website"
+           ",email"
+           ",logo)"
+           "VALUES"
+           "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, 
$16, $17, $18)");
+  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                           "insert_instance",
+                                           params);
+  if (qs <= 0)
+    return qs;
+  PREPARE (pg,
+           "insert_keys",
+           "INSERT INTO merchant_keys"
+           "(merchant_priv"
+           ",merchant_serial)"
+           " SELECT $1, merchant_serial"
+           " FROM merchant_instances"
+           " WHERE merchant_id=$2");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_keys",
+                                             params_priv);
+}
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_insert_instance.h
similarity index 53%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_insert_instance.h
index 463bc527..5b347363 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_insert_instance.h
@@ -14,30 +14,32 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_insert_instance.h
+ * @brief implementation of the insert_instance function for Postgres
+ * @author Iván Ávalos
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_INSERT_INSTANCE_H
+#define PG_INSERT_INSTANCE_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Insert information about an instance into our database.
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
+ * @param merchant_pub public key of the instance
+ * @param merchant_priv private key of the instance
+ * @param is details about the instance
+ * @param ias authentication settings for the instance
  * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
-
+TMH_PG_insert_instance (void *cls,
+                        const struct TALER_MerchantPublicKeyP *merchant_pub,
+                        const struct TALER_MerchantPrivateKeyP *merchant_priv,
+                        const struct TALER_MERCHANTDB_InstanceSettings *is,
+                        const struct TALER_MERCHANTDB_InstanceAuthSettings 
*ias);
 
 #endif
diff --git a/src/backenddb/pg_insert_product.c 
b/src/backenddb/pg_insert_product.c
new file mode 100644
index 00000000..8ee2b274
--- /dev/null
+++ b/src/backenddb/pg_insert_product.c
@@ -0,0 +1,76 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_product.c
+ * @brief Implementation of the insert_product function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_product.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_product (void *cls,
+                       const char *instance_id,
+                       const char *product_id,
+                       const struct TALER_MERCHANTDB_ProductDetails *pd)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (product_id),
+    GNUNET_PQ_query_param_string (pd->description),
+    TALER_PQ_query_param_json (pd->description_i18n),
+    GNUNET_PQ_query_param_string (pd->unit),
+    GNUNET_PQ_query_param_string (pd->image),
+    TALER_PQ_query_param_json (pd->taxes),
+    TALER_PQ_query_param_amount (&pd->price),
+    GNUNET_PQ_query_param_uint64 (&pd->total_stock),
+    TALER_PQ_query_param_json (pd->address),
+    GNUNET_PQ_query_param_timestamp (&pd->next_restock),
+    GNUNET_PQ_query_param_uint32 (&pd->minimum_age),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "insert_product",
+           "INSERT INTO merchant_inventory"
+           "(merchant_serial"
+           ",product_id"
+           ",description"
+           ",description_i18n"
+           ",unit"
+           ",image"
+           ",taxes"
+           ",price_val"
+           ",price_frac"
+           ",total_stock"
+           ",address"
+           ",next_restock"
+           ",minimum_age"
+           ")"
+           " SELECT merchant_serial,"
+           " $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13"
+           " FROM merchant_instances"
+           " WHERE merchant_id=$1");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_product",
+                                             params);
+}
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_insert_product.h
similarity index 60%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_insert_product.h
index 463bc527..169bd150 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_insert_product.h
@@ -14,30 +14,30 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_insert_product.h
+ * @brief implementation of the insert_product function for Postgres
+ * @author Iván Ávalos
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_INSERT_PRODUCT_H
+#define PG_INSERT_PRODUCT_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Insert details about a particular product.
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
+ * @param instance_id instance to insert product for
+ * @param product_id product identifier of product to insert
+ * @param pd the product details to insert
  * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
-
+TMH_PG_insert_product (void *cls,
+                       const char *instance_id,
+                       const char *product_id,
+                       const struct TALER_MERCHANTDB_ProductDetails *pd);
 
 #endif
diff --git a/src/backenddb/pg_lock_product.c b/src/backenddb/pg_lock_product.c
new file mode 100644
index 00000000..205f0b67
--- /dev/null
+++ b/src/backenddb/pg_lock_product.c
@@ -0,0 +1,76 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lock_product.c
+ * @brief Implementation of the lock_product function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lock_product.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lock_product (void *cls,
+                     const char *instance_id,
+                     const char *product_id,
+                     const struct GNUNET_Uuid *uuid,
+                     uint64_t quantity,
+                     struct GNUNET_TIME_Timestamp expiration_time)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (product_id),
+    GNUNET_PQ_query_param_auto_from_type (uuid),
+    GNUNET_PQ_query_param_uint64 (&quantity),
+    GNUNET_PQ_query_param_timestamp (&expiration_time),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "lock_product",
+           "WITH ps AS"
+           "  (SELECT product_serial"
+           "   FROM merchant_inventory"
+           "   WHERE product_id=$2"
+           "     AND merchant_serial="
+           "     (SELECT merchant_serial"
+           "        FROM merchant_instances"
+           "        WHERE merchant_id=$1))"
+           "INSERT INTO merchant_inventory_locks"
+           "(product_serial"
+           ",lock_uuid"
+           ",total_locked"
+           ",expiration)"
+           " SELECT product_serial, $3, $4, $5"
+           "   FROM merchant_inventory"
+           "   JOIN ps USING (product_serial)"
+           "   WHERE "
+           "     total_stock - total_sold - total_lost - $4 >= "
+           "     (SELECT COALESCE(SUM(total_locked), 0)"
+           "        FROM merchant_inventory_locks"
+           "        WHERE product_serial=ps.product_serial) + "
+           "     (SELECT COALESCE(SUM(total_locked), 0)"
+           "        FROM merchant_order_locks"
+           "        WHERE product_serial=ps.product_serial)");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "lock_product",
+                                             params);
+}
diff --git a/src/backenddb/pg_lock_product.h b/src/backenddb/pg_lock_product.h
new file mode 100644
index 00000000..d0e13d41
--- /dev/null
+++ b/src/backenddb/pg_lock_product.h
@@ -0,0 +1,49 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lock_product.h
+ * @brief implementation of the lock_product function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOCK_PRODUCT_H
+#define PG_LOCK_PRODUCT_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Lock stocks of a particular product. Note that the transaction must
+ * enforce that the "stocked-sold-lost >= locked" constraint holds.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup products for
+ * @param product_id product to lookup
+ * @param uuid the UUID that holds the lock
+ * @param quantity how many units should be locked
+ * @param expiration_time when should the lock expire
+ * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the
+ *         product is unknown OR if there insufficient stocks remaining
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lock_product (void *cls,
+                     const char *instance_id,
+                     const char *product_id,
+                     const struct GNUNET_Uuid *uuid,
+                     uint64_t quantity,
+                     struct GNUNET_TIME_Timestamp expiration_time);
+
+#endif
diff --git a/src/backenddb/pg_lookup_instance_auth.c 
b/src/backenddb/pg_lookup_instance_auth.c
new file mode 100644
index 00000000..1360cce9
--- /dev/null
+++ b/src/backenddb/pg_lookup_instance_auth.c
@@ -0,0 +1,59 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_instance_auth.c
+ * @brief Implementation of the lookup_instance_auth function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_instance_auth.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_instance_auth (
+  void *cls,
+  const char *instance_id,
+  struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("auth_hash",
+                                          &ias->auth_hash),
+    GNUNET_PQ_result_spec_auto_from_type ("auth_salt",
+                                          &ias->auth_salt),
+    GNUNET_PQ_result_spec_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "lookup_instance_auth",
+           "SELECT"
+           " auth_hash"
+           ",auth_salt"
+           " FROM merchant_instances"
+           " WHERE merchant_id=$1");
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "lookup_instance_auth",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/backenddb/pg_delete_exchange_accounts.h 
b/src/backenddb/pg_lookup_instance_auth.h
similarity index 62%
copy from src/backenddb/pg_delete_exchange_accounts.h
copy to src/backenddb/pg_lookup_instance_auth.h
index da9013d3..ff788a79 100644
--- a/src/backenddb/pg_delete_exchange_accounts.h
+++ b/src/backenddb/pg_lookup_instance_auth.h
@@ -14,29 +14,27 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_delete_exchange_accounts.h
- * @brief implementation of the delete_exchange_accounts function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_lookup_instance_auth.h
+ * @brief implementation of the lookup_instance_auth function for Postgres
+ * @author Iván Ávalos
  */
-#ifndef PG_DELETE_EXCHANGE_ACCOUNTS_H
-#define PG_DELETE_EXCHANGE_ACCOUNTS_H
+#ifndef PG_LOOKUP_INSTANCE_AUTH_H
+#define PG_LOOKUP_INSTANCE_AUTH_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
-
 /**
- * Delete information about wire accounts of an exchange. (Used when we got 
new account data.)
+ * Lookup authentication data of an instance.
  *
  * @param cls closure
- * @param master_pub public key of the exchange
- * @return transaction status code
+ * @param instance_id instance to query
+ * @param[out] ias where to store the auth data
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_delete_exchange_accounts (
-  void *cls,
-  const struct TALER_MasterPublicKeyP *master_pub);
-
+TMH_PG_lookup_instance_auth (void *cls,
+                             const char *instance_id,
+                             struct TALER_MERCHANTDB_InstanceAuthSettings 
*ias);
 
 #endif
diff --git a/src/backenddb/pg_lookup_product.c 
b/src/backenddb/pg_lookup_product.c
new file mode 100644
index 00000000..d9eb0915
--- /dev/null
+++ b/src/backenddb/pg_lookup_product.c
@@ -0,0 +1,110 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_product.c
+ * @brief Implementation of the lookup_product function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_product.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_product (void *cls,
+                       const char *instance_id,
+                       const char *product_id,
+                       struct TALER_MERCHANTDB_ProductDetails *pd)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (product_id),
+    GNUNET_PQ_query_param_end
+  };
+
+  if (NULL == pd)
+  {
+    struct GNUNET_PQ_ResultSpec rs_null[] = {
+      GNUNET_PQ_result_spec_end
+    };
+
+    check_connection (pg);
+    return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                     "lookup_product",
+                                                     params,
+                                                     rs_null);
+  }
+  else
+  {
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_string ("description",
+                                    &pd->description),
+      TALER_PQ_result_spec_json ("description_i18n",
+                                 &pd->description_i18n),
+      GNUNET_PQ_result_spec_string ("unit",
+                                    &pd->unit),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("price",
+                                   &pd->price),
+      TALER_PQ_result_spec_json ("taxes",
+                                 &pd->taxes),
+      GNUNET_PQ_result_spec_uint64 ("total_stock",
+                                    &pd->total_stock),
+      GNUNET_PQ_result_spec_uint64 ("total_sold",
+                                    &pd->total_sold),
+      GNUNET_PQ_result_spec_uint64 ("total_lost",
+                                    &pd->total_lost),
+      GNUNET_PQ_result_spec_string ("image",
+                                    &pd->image),
+      TALER_PQ_result_spec_json ("address",
+                                 &pd->address),
+      GNUNET_PQ_result_spec_timestamp ("next_restock",
+                                       &pd->next_restock),
+      GNUNET_PQ_result_spec_uint32 ("minimum_age",
+                                    &pd->minimum_age),
+      GNUNET_PQ_result_spec_end
+    };
+
+    check_connection (pg);
+    PREPARE (pg,
+             "lookup_product",
+             "SELECT"
+             " description"
+             ",description_i18n"
+             ",unit"
+             ",price_val"
+             ",price_frac"
+             ",taxes"
+             ",total_stock"
+             ",total_sold"
+             ",total_lost"
+             ",image"
+             ",merchant_inventory.address"
+             ",next_restock"
+             ",minimum_age"
+             " FROM merchant_inventory"
+             " JOIN merchant_instances"
+             "   USING (merchant_serial)"
+             " WHERE merchant_instances.merchant_id=$1"
+             "   AND merchant_inventory.product_id=$2");
+    return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                     "lookup_product",
+                                                     params,
+                                                     rs);
+  }
+}
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_lookup_product.h
similarity index 57%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_lookup_product.h
index 463bc527..a6add4cb 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_lookup_product.h
@@ -14,30 +14,31 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_lookup_product.h
+ * @brief implementation of the lookup_product function for Postgres
+ * @author Iván Ávalos
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_LOOKUP_PRODUCT_H
+#define PG_LOOKUP_PRODUCT_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Lookup details about a particular product.
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
+ * @param instance_id instance to lookup products for
+ * @param product_id product to lookup
+ * @param[out] pd set to the product details on success, can be NULL
+ *             (in that case we only want to check if the product exists)
  * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
-
+TMH_PG_lookup_product (void *cls,
+                       const char *instance_id,
+                       const char *product_id,
+                       struct TALER_MERCHANTDB_ProductDetails *pd);
 
 #endif
diff --git a/src/backenddb/pg_lookup_products.c 
b/src/backenddb/pg_lookup_products.c
new file mode 100644
index 00000000..c04ad5f2
--- /dev/null
+++ b/src/backenddb/pg_lookup_products.c
@@ -0,0 +1,126 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_products.c
+ * @brief Implementation of the lookup_products function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_products.h"
+#include "pg_helper.h"
+
+/**
+ * Context used for postgres_lookup_products().
+ */
+struct LookupProductsContext
+{
+  /**
+   * Function to call with the results.
+   */
+  TALER_MERCHANTDB_ProductsCallback cb;
+
+  /**
+   * Closure for @a cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Did database result extraction fail?
+   */
+  bool extract_failed;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results about products.
+ *
+ * @param[in,out] cls of type `struct LookupProductsContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lookup_products_cb (void *cls,
+                    PGresult *result,
+                    unsigned int num_results)
+{
+  struct LookupProductsContext *plc = cls;
+
+  for (unsigned int i = 0; i < num_results; i++)
+  {
+    char *product_id;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_string ("product_id",
+                                    &product_id),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      plc->extract_failed = true;
+      return;
+    }
+    plc->cb (plc->cb_cls,
+             product_id);
+    GNUNET_PQ_cleanup_result (rs);
+  }
+}
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_products (void *cls,
+                        const char *instance_id,
+                        TALER_MERCHANTDB_ProductsCallback cb,
+                        void *cb_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct LookupProductsContext plc = {
+    .cb = cb,
+    .cb_cls = cb_cls,
+    /* Can be overwritten by the lookup_products_cb */
+    .extract_failed = false,
+  };
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  check_connection (pg);
+  PREPARE (pg,
+           "lookup_products",
+           "SELECT"
+           " product_id"
+           " FROM merchant_inventory"
+           " JOIN merchant_instances"
+           "   USING (merchant_serial)"
+           " WHERE merchant_instances.merchant_id=$1");
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                             "lookup_products",
+                                             params,
+                                             &lookup_products_cb,
+                                             &plc);
+  /* If there was an error inside lookup_products_cb, return a hard error. */
+  if (plc.extract_failed)
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  return qs;
+}
diff --git a/src/backenddb/pg_select_wirewatch_accounts.h 
b/src/backenddb/pg_lookup_products.h
similarity index 61%
copy from src/backenddb/pg_select_wirewatch_accounts.h
copy to src/backenddb/pg_lookup_products.h
index cff263d3..398b5eac 100644
--- a/src/backenddb/pg_select_wirewatch_accounts.h
+++ b/src/backenddb/pg_lookup_products.h
@@ -14,31 +14,30 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_select_wirewatch_accounts.h
- * @brief implementation of the select_wirewatch_accounts function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_lookup_products.h
+ * @brief implementation of the lookup_products function for Postgres
+ * @author Iván Ávalos
  */
-#ifndef PG_SELECT_WIREWATCH_ACCOUNTS_H
-#define PG_SELECT_WIREWATCH_ACCOUNTS_H
+#ifndef PG_LOOKUP_PRODUCTS_H
+#define PG_LOOKUP_PRODUCTS_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
-
 /**
- * Select information about progress made by taler-merchant-wirewatch.
+ * Lookup all of the products the given instance has configured.
  *
  * @param cls closure
- * @param cb function to call with results
+ * @param instance_id instance to lookup products for
+ * @param cb function to call on all products found
  * @param cb_cls closure for @a cb
- * @return transaction status
+ * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_select_wirewatch_accounts (
-  void *cls,
-  TALER_MERCHANTDB_WirewatchWorkCallback cb,
-  void *cb_cls);
-
+TMH_PG_lookup_products (void *cls,
+                        const char *instance_id,
+                        TALER_MERCHANTDB_ProductsCallback cb,
+                        void *cb_cls);
 
 #endif
diff --git a/src/backenddb/pg_delete_exchange_accounts.c 
b/src/backenddb/pg_purge_instance.c
similarity index 60%
copy from src/backenddb/pg_delete_exchange_accounts.c
copy to src/backenddb/pg_purge_instance.c
index 7d8a5e48..74ca5613 100644
--- a/src/backenddb/pg_delete_exchange_accounts.c
+++ b/src/backenddb/pg_purge_instance.c
@@ -14,35 +14,41 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_delete_exchange_accounts.c
- * @brief Implementation of the delete_exchange_accounts function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_purge_instance.c
+ * @brief Implementation of the purge_instance function for Postgres
+ * @author Iván Ávalos
  */
 #include "platform.h"
 #include <taler/taler_error_codes.h>
 #include <taler/taler_dbevents.h>
 #include <taler/taler_pq_lib.h>
-#include "pg_delete_exchange_accounts.h"
+#include "pg_purge_instance.h"
 #include "pg_helper.h"
 
-
+/**
+ * Purge an instance and all associated information from our database.
+ * Highly likely to cause undesired data loss. Use with caution.
+ *
+ * @param cls closure
+ * @param merchant_id identifier of the instance
+ * @return database result code
+ */
 enum GNUNET_DB_QueryStatus
-TMH_PG_delete_exchange_accounts (
-  void *cls,
-  const struct TALER_MasterPublicKeyP *master_pub)
+TMH_PG_purge_instance (void *cls,
+                       const char *merchant_id)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (master_pub),
+    GNUNET_PQ_query_param_string (merchant_id),
     GNUNET_PQ_query_param_end
   };
 
   check_connection (pg);
   PREPARE (pg,
-           "delete_exchange_accounts",
-           "DELETE FROM merchant_exchange_accounts"
-           " WHERE master_pub=$1;");
+           "purge_instance",
+           "DELETE FROM merchant_instances"
+           " WHERE merchant_instances.merchant_id = $1");
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "delete_exchange_accounts",
+                                             "purge_instance",
                                              params);
 }
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_purge_instance.h
similarity index 68%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_purge_instance.h
index 463bc527..3df05bd8 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_purge_instance.h
@@ -14,30 +14,27 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
+ * @file backenddb/pg_purge_instance.h
+ * @brief implementation of the purge_instance function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_PURGE_INSTANCE_H
+#define PG_PURGE_INSTANCE_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Purge an instance and all associated information from our database.
+ * Highly likely to cause undesired data loss. Use with caution.
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
+ * @param merchant_id identifier of the instance
  * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
-
+TMH_PG_purge_instance (void *cls,
+                       const char *merchant_id);
 
 #endif
diff --git a/src/backenddb/pg_update_instance.c 
b/src/backenddb/pg_update_instance.c
new file mode 100644
index 00000000..5de6032d
--- /dev/null
+++ b/src/backenddb/pg_update_instance.c
@@ -0,0 +1,80 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_update_instance.c
+ * @brief Implementation of the update_instance function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_update_instance.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_instance (void *cls,
+                        const struct TALER_MERCHANTDB_InstanceSettings *is)
+{
+  struct PostgresClosure *pg = cls;
+  uint32_t ut32 = (uint32_t) is->ut;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (is->id),
+    GNUNET_PQ_query_param_string (is->name),
+    TALER_PQ_query_param_json (is->address),
+    TALER_PQ_query_param_json (is->jurisdiction),
+    TALER_PQ_query_param_amount (&is->default_max_deposit_fee),
+    TALER_PQ_query_param_amount (&is->default_max_wire_fee),
+    GNUNET_PQ_query_param_uint32 (&is->default_wire_fee_amortization),
+    GNUNET_PQ_query_param_relative_time (
+      &is->default_wire_transfer_delay),
+    GNUNET_PQ_query_param_relative_time (&is->default_pay_delay),
+    (NULL == is->website)
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_string (is->website),
+    (NULL == is->email)
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_string (is->email),
+    (NULL == is->logo)
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_string (is->logo),
+    GNUNET_PQ_query_param_uint32 (&ut32),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "update_instance",
+           "UPDATE merchant_instances SET"
+           " merchant_name=$2"
+           ",address=$3"
+           ",jurisdiction=$4"
+           ",default_max_deposit_fee_val=$5"
+           ",default_max_deposit_fee_frac=$6"
+           ",default_max_wire_fee_val=$7"
+           ",default_max_wire_fee_frac=$8"
+           ",default_wire_fee_amortization=$9"
+           ",default_wire_transfer_delay=$10"
+           ",default_pay_delay=$11"
+           ",website=$12"
+           ",email=$13"
+           ",logo=$14"
+           ",user_type=$15"
+           " WHERE merchant_id=$1");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "update_instance",
+                                             params);
+}
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_update_instance.h
similarity index 65%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_update_instance.h
index 463bc527..9c8c1d22 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_update_instance.h
@@ -14,30 +14,26 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_update_instance.h
+ * @brief implementation of the update_instance function for Postgres
+ * @author Iván Ávalos
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_UPDATE_INSTANCE_H
+#define PG_UPDATE_INSTANCE_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Update information about an instance into our database.
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
+ * @param is details about the instance
  * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
-
+TMH_PG_update_instance (void *cls,
+                        const struct TALER_MERCHANTDB_InstanceSettings *is);
 
 #endif
diff --git a/src/backenddb/pg_delete_exchange_accounts.c 
b/src/backenddb/pg_update_instance_auth.c
similarity index 62%
copy from src/backenddb/pg_delete_exchange_accounts.c
copy to src/backenddb/pg_update_instance_auth.c
index 7d8a5e48..d7077761 100644
--- a/src/backenddb/pg_delete_exchange_accounts.c
+++ b/src/backenddb/pg_update_instance_auth.c
@@ -14,35 +14,39 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_delete_exchange_accounts.c
- * @brief Implementation of the delete_exchange_accounts function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_update_instance_auth.c
+ * @brief Implementation of the update_instance_auth function for Postgres
+ * @author Iván Ávalos
  */
 #include "platform.h"
 #include <taler/taler_error_codes.h>
 #include <taler/taler_dbevents.h>
 #include <taler/taler_pq_lib.h>
-#include "pg_delete_exchange_accounts.h"
+#include "pg_update_instance_auth.h"
 #include "pg_helper.h"
 
-
 enum GNUNET_DB_QueryStatus
-TMH_PG_delete_exchange_accounts (
+TMH_PG_update_instance_auth (
   void *cls,
-  const struct TALER_MasterPublicKeyP *master_pub)
+  const char *merchant_id,
+  const struct TALER_MERCHANTDB_InstanceAuthSettings *is)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (master_pub),
+    GNUNET_PQ_query_param_string (merchant_id),
+    GNUNET_PQ_query_param_auto_from_type (&is->auth_hash),
+    GNUNET_PQ_query_param_auto_from_type (&is->auth_salt),
     GNUNET_PQ_query_param_end
   };
 
   check_connection (pg);
   PREPARE (pg,
-           "delete_exchange_accounts",
-           "DELETE FROM merchant_exchange_accounts"
-           " WHERE master_pub=$1;");
+           "update_instance_auth",
+           "UPDATE merchant_instances SET"
+           " auth_hash=$2"
+           ",auth_salt=$3"
+           " WHERE merchant_id=$1");
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "delete_exchange_accounts",
+                                             "update_instance_auth",
                                              params);
 }
diff --git a/src/backenddb/pg_insert_account.h 
b/src/backenddb/pg_update_instance_auth.h
similarity index 60%
copy from src/backenddb/pg_insert_account.h
copy to src/backenddb/pg_update_instance_auth.h
index 463bc527..cf0bc963 100644
--- a/src/backenddb/pg_insert_account.h
+++ b/src/backenddb/pg_update_instance_auth.h
@@ -14,30 +14,29 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file backenddb/pg_insert_account.h
- * @brief implementation of the insert_account function for Postgres
- * @author Christian Grothoff
+ * @file backenddb/pg_update_instance_auth.h
+ * @brief implementation of the update_instance_auth function for Postgres
+ * @author Iván Ávalos
  */
-#ifndef PG_INSERT_ACCOUNT_H
-#define PG_INSERT_ACCOUNT_H
+#ifndef PG_UPDATE_INSTANCE_AUTH_H
+#define PG_UPDATE_INSTANCE_AUTH_H
 
 #include <taler/taler_util.h>
 #include <taler/taler_json_lib.h>
 #include "taler_merchantdb_plugin.h"
 
 /**
- * Insert information about an instance's account into our database.
+ * Update information about an instance's authentication settings
+ * into our database.
  *
  * @param cls closure
- * @param id identifier of the instance
- * @param account_details details about the account
+ * @param merchant_id identity of the instance
+ * @param is authentication details about the instance
  * @return database result code
  */
 enum GNUNET_DB_QueryStatus
-TMH_PG_insert_account (
-  void *cls,
-  const char *id,
-  const struct TALER_MERCHANTDB_AccountDetails *account_details);
-
+TMH_PG_update_instance_auth (void *cls,
+                             const char *merchant_id,
+                             const struct 
TALER_MERCHANTDB_InstanceAuthSettings *is);
 
 #endif
diff --git a/src/backenddb/pg_update_product.c 
b/src/backenddb/pg_update_product.c
new file mode 100644
index 00000000..b571a8fe
--- /dev/null
+++ b/src/backenddb/pg_update_product.c
@@ -0,0 +1,85 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_update_product.c
+ * @brief Implementation of the update_product function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_update_product.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_product (void *cls,
+                       const char *instance_id,
+                       const char *product_id,
+                       const struct TALER_MERCHANTDB_ProductDetails *pd)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id), /* $1 */
+    GNUNET_PQ_query_param_string (product_id),
+    GNUNET_PQ_query_param_string (pd->description),
+    TALER_PQ_query_param_json (pd->description_i18n),
+    GNUNET_PQ_query_param_string (pd->unit),
+    GNUNET_PQ_query_param_string (pd->image), /* $6 */
+    TALER_PQ_query_param_json (pd->taxes),
+    TALER_PQ_query_param_amount (&pd->price), /* $8+$9 */
+    GNUNET_PQ_query_param_uint64 (&pd->total_stock),  /* $10 */
+    GNUNET_PQ_query_param_uint64 (&pd->total_lost),
+    TALER_PQ_query_param_json (pd->address),
+    GNUNET_PQ_query_param_timestamp (&pd->next_restock),
+    GNUNET_PQ_query_param_uint32 (&pd->minimum_age),
+    GNUNET_PQ_query_param_end
+  };
+
+  if ( (pd->total_stock < pd->total_lost + pd->total_sold) ||
+       (pd->total_lost < pd->total_lost
+        + pd->total_sold) /* integer overflow */)
+  {
+    GNUNET_break (0);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+  check_connection (pg);
+  PREPARE (pg,
+           "update_product",
+           "UPDATE merchant_inventory SET"
+           " description=$3"
+           ",description_i18n=$4"
+           ",unit=$5"
+           ",image=$6"
+           ",taxes=$7"
+           ",price_val=$8"
+           ",price_frac=$9"
+           ",total_stock=$10"
+           ",total_lost=$11"
+           ",address=$12"
+           ",next_restock=$13"
+           ",minimum_age=$14"
+           " WHERE merchant_serial="
+           "   (SELECT merchant_serial"
+           "      FROM merchant_instances"
+           "      WHERE merchant_id=$1)"
+           "   AND product_id=$2"
+           "   AND total_stock <= $10"
+           "   AND total_lost <= $11");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "update_product",
+                                             params);
+}
diff --git a/src/backenddb/pg_update_product.h 
b/src/backenddb/pg_update_product.h
new file mode 100644
index 00000000..3ad280ef
--- /dev/null
+++ b/src/backenddb/pg_update_product.h
@@ -0,0 +1,53 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_update_product.h
+ * @brief implementation of the update_product function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_UPDATE_PRODUCT_H
+#define PG_UPDATE_PRODUCT_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Update details about a particular product. Note that the
+ * transaction must enforce that the sold/stocked/lost counters
+ * are not reduced (i.e. by expanding the WHERE clause on the existing
+ * values).
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup products for
+ * @param product_id product to lookup
+ * @param[out] pd set to the product details on success, can be NULL
+ *             (in that case we only want to check if the product exists)
+ *             total_sold in @a pd is ignored, total_lost must not
+ *             exceed total_stock minus the existing total_sold;
+ *             total_sold and total_stock must be larger or equal to
+ *             the existing value;
+ * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the
+ *         non-decreasing constraints are not met *or* if the product
+ *         does not yet exist.
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_product (void *cls,
+                       const char *instance_id,
+                       const char *product_id,
+                       const struct TALER_MERCHANTDB_ProductDetails *pd);
+
+#endif
diff --git a/src/backenddb/plugin_merchantdb_postgres.c 
b/src/backenddb/plugin_merchantdb_postgres.c
index 710fbdb3..0e5f921f 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -20,6 +20,7 @@
  * @author Christian Grothoff
  * @author Marcello Stanisci
  * @author Priscilla Huang
+ * @author Iván Ávalos
  */
 #include "platform.h"
 #include <gnunet/gnunet_util_lib.h>
@@ -41,7 +42,23 @@
 #include "pg_select_accounts_by_exchange.h"
 #include "pg_insert_exchange_account.h"
 #include "pg_lookup_reserves.h"
+#include "pg_lookup_instance_auth.h"
 #include "pg_update_transfer_status.h"
+#include "pg_insert_instance.h"
+#include "pg_account_kyc_set_status.h"
+#include "pg_account_kyc_get_status.h"
+#include "pg_delete_instance_private_key.h"
+#include "pg_purge_instance.h"
+#include "pg_update_instance.h"
+#include "pg_update_instance_auth.h"
+#include "pg_inactivate_account.h"
+#include "pg_activate_account.h"
+#include "pg_lookup_products.h"
+#include "pg_lookup_product.h"
+#include "pg_delete_product.h"
+#include "pg_insert_product.h"
+#include "pg_update_product.h"
+#include "pg_lock_product.h"
 #include "pg_set_transfer_status_to_confirmed.h"
 
 
@@ -319,844 +336,6 @@ postgres_commit (void *cls)
 }
 
 
-/**
- * Lookup authentication data of an instance.
- *
- * @param cls closure
- * @param instance_id instance to query
- * @param[out] ias where to store the auth data
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_instance_auth (
-  void *cls,
-  const char *instance_id,
-  struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("auth_hash",
-                                          &ias->auth_hash),
-    GNUNET_PQ_result_spec_auto_from_type ("auth_salt",
-                                          &ias->auth_salt),
-    GNUNET_PQ_result_spec_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "lookup_instance_auth",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Insert information about an instance into our database.
- *
- * @param cls closure
- * @param merchant_pub public key of the instance
- * @param merchant_priv private key of the instance
- * @param is details about the instance
- * @param ias authentication settings for the instance
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_instance (
-  void *cls,
-  const struct TALER_MerchantPublicKeyP *merchant_pub,
-  const struct TALER_MerchantPrivateKeyP *merchant_priv,
-  const struct TALER_MERCHANTDB_InstanceSettings *is,
-  const struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
-{
-  struct PostgresClosure *pg = cls;
-  uint32_t ut32 = (uint32_t) is->ut;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (merchant_pub),
-    GNUNET_PQ_query_param_auto_from_type (&ias->auth_hash),
-    GNUNET_PQ_query_param_auto_from_type (&ias->auth_salt),
-    GNUNET_PQ_query_param_string (is->id),
-    GNUNET_PQ_query_param_string (is->name),
-    GNUNET_PQ_query_param_uint32 (&ut32),
-    TALER_PQ_query_param_json (is->address),
-    TALER_PQ_query_param_json (is->jurisdiction),
-    TALER_PQ_query_param_amount (&is->default_max_deposit_fee),
-    TALER_PQ_query_param_amount (&is->default_max_wire_fee),
-    GNUNET_PQ_query_param_uint32 (&is->default_wire_fee_amortization),
-    GNUNET_PQ_query_param_relative_time (
-      &is->default_wire_transfer_delay),
-    GNUNET_PQ_query_param_relative_time (&is->default_pay_delay),
-    (NULL == is->website)
-    ? GNUNET_PQ_query_param_null ()
-    : GNUNET_PQ_query_param_string (is->website),
-    (NULL == is->email)
-    ? GNUNET_PQ_query_param_null ()
-    : GNUNET_PQ_query_param_string (is->email),
-    (NULL == is->logo)
-    ? GNUNET_PQ_query_param_null ()
-    : GNUNET_PQ_query_param_string (is->logo),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_QueryParam params_priv[] = {
-    GNUNET_PQ_query_param_auto_from_type (merchant_priv),
-    GNUNET_PQ_query_param_string (is->id),
-    GNUNET_PQ_query_param_end
-  };
-  enum GNUNET_DB_QueryStatus qs;
-
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                           "insert_instance",
-                                           params);
-  if (qs <= 0)
-    return qs;
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_keys",
-                                             params_priv);
-}
-
-
-/**
- * Closure for kyc_status_cb().
- */
-struct KycStatusContext
-{
-  /**
-   * Function to call with results.
-   */
-  TALER_MERCHANTDB_KycCallback kyc_cb;
-
-  /**
-   * Closure for @e kyc_cb.
-   */
-  void *kyc_cb_cls;
-
-  /**
-   * Filter, NULL to not filter.
-   */
-  const struct TALER_MerchantWireHashP *h_wire;
-
-  /**
-   * Filter, NULL to not filter.
-   */
-  const char *exchange_url;
-
-  /**
-   * Number of results found.
-   */
-  unsigned int count;
-
-  /**
-   * Set to true on failure(s).
-   */
-  bool failure;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param[in,out] cls of type `struct KycStatusContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-kyc_status_cb (void *cls,
-               PGresult *result,
-               unsigned int num_results)
-{
-  struct KycStatusContext *ksc = cls;
-
-  for (unsigned int i = 0; i < num_results; i++)
-  {
-    struct TALER_MerchantWireHashP h_wire;
-    uint64_t kyc_serial;
-    char *exchange_url;
-    char *payto_uri;
-    struct GNUNET_TIME_Timestamp last_check;
-    bool kyc_ok;
-    uint32_t aml_decision;
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_auto_from_type ("h_wire",
-                                            &h_wire),
-      GNUNET_PQ_result_spec_uint64 ("exchange_kyc_serial",
-                                    &kyc_serial),
-      GNUNET_PQ_result_spec_string ("payto_uri",
-                                    &payto_uri),
-      GNUNET_PQ_result_spec_string ("exchange_url",
-                                    &exchange_url),
-      GNUNET_PQ_result_spec_timestamp ("kyc_timestamp",
-                                       &last_check),
-      GNUNET_PQ_result_spec_bool ("kyc_ok",
-                                  &kyc_ok),
-      GNUNET_PQ_result_spec_uint32 ("aml_decision",
-                                    &aml_decision),
-      GNUNET_PQ_result_spec_end
-    };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      ksc->failure = true;
-      return;
-    }
-    if ( (NULL != ksc->exchange_url) &&
-         (0 != strcmp (ksc->exchange_url,
-                       exchange_url)) )
-    {
-      GNUNET_PQ_cleanup_result (rs);
-      continue;
-    }
-    if ( (NULL != ksc->h_wire) &&
-         (0 != GNUNET_memcmp (ksc->h_wire,
-                              &h_wire)) )
-    {
-      GNUNET_PQ_cleanup_result (rs);
-      continue;
-    }
-    ksc->count++;
-    ksc->kyc_cb (ksc->kyc_cb_cls,
-                 &h_wire,
-                 kyc_serial,
-                 payto_uri,
-                 exchange_url,
-                 last_check,
-                 kyc_ok,
-                 (enum TALER_AmlDecisionState) aml_decision);
-    GNUNET_PQ_cleanup_result (rs);
-  }
-}
-
-
-/**
- * Check an instance's account's KYC status.
- *
- * @param cls closure
- * @param merchant_id merchant backend instance ID
- * @param h_wire hash of the wire account to check,
- *        NULL to check all accounts of the merchant
- * @param exchange_url base URL of the exchange to check,
- *        NULL to check all exchanges
- * @param kyc_cb KYC status callback to invoke
- * @param kyc_cb_cls closure for @a kyc_cb
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_account_kyc_get_status (void *cls,
-                                 const char *merchant_id,
-                                 const struct TALER_MerchantWireHashP *h_wire,
-                                 const char *exchange_url,
-                                 TALER_MERCHANTDB_KycCallback kyc_cb,
-                                 void *kyc_cb_cls)
-{
-  struct PostgresClosure *pg = cls;
-  struct KycStatusContext ksc = {
-    .kyc_cb = kyc_cb,
-    .kyc_cb_cls = kyc_cb_cls,
-    .exchange_url = exchange_url,
-    .h_wire = h_wire
-  };
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (merchant_id),
-    GNUNET_PQ_query_param_end
-  };
-  enum GNUNET_DB_QueryStatus qs;
-
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                             "lookup_kyc_status",
-                                             params,
-                                             &kyc_status_cb,
-                                             &ksc);
-  if (ksc.failure)
-  {
-    GNUNET_break (0);
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  }
-  if (0 > qs)
-    return qs;
-  return ksc.count;
-}
-
-
-/**
- * Update an instance's account's KYC status.
- *
- * @param cls closure
- * @param merchant_id merchant backend instance ID
- * @param h_wire hash of the wire account to check
- * @param exchange_url base URL of the exchange to check
- * @param exchange_kyc_serial serial number for our account at the exchange (0 
if unknown)
- * @param exchange_sig signature of the exchange, or NULL for none
- * @param exchange_pub public key of the exchange, or NULL for none
- * @param timestamp timestamp to store
- * @param kyc_ok current KYC status (true for satisfied)
- * @param aml_decision current AML decision state at the exchange
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_account_kyc_set_status (
-  void *cls,
-  const char *merchant_id,
-  const struct TALER_MerchantWireHashP *h_wire,
-  const char *exchange_url,
-  uint64_t exchange_kyc_serial,
-  const struct TALER_ExchangeSignatureP *exchange_sig,
-  const struct TALER_ExchangePublicKeyP *exchange_pub,
-  struct GNUNET_TIME_Timestamp timestamp,
-  bool kyc_ok,
-  enum TALER_AmlDecisionState aml_decision)
-{
-  struct PostgresClosure *pg = cls;
-  uint32_t aml32 = (uint32_t) aml_decision;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (merchant_id),
-    GNUNET_PQ_query_param_auto_from_type (h_wire),
-    GNUNET_PQ_query_param_string (exchange_url),
-    GNUNET_PQ_query_param_uint64 (&exchange_kyc_serial),
-    GNUNET_PQ_query_param_timestamp (&timestamp),
-    GNUNET_PQ_query_param_bool (kyc_ok),
-    exchange_pub
-    ? GNUNET_PQ_query_param_auto_from_type (exchange_pub)
-    : GNUNET_PQ_query_param_null (),
-    exchange_sig
-    ? GNUNET_PQ_query_param_auto_from_type (exchange_sig)
-    : GNUNET_PQ_query_param_null (),
-    GNUNET_PQ_query_param_uint32 (&aml32),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "upsert_account_kyc",
-                                             params);
-}
-
-
-/**
- * Delete private key of an instance from our database.
- *
- * @param cls closure
- * @param merchant_id identifier of the instance
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_instance_private_key (
-  void *cls,
-  const char *merchant_id)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (merchant_id),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "delete_key",
-                                             params);
-}
-
-
-/**
- * Purge an instance and all associated information from our database.
- * Highly likely to cause undesired data loss. Use with caution.
- *
- * @param cls closure
- * @param merchant_id identifier of the instance
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_purge_instance (void *cls,
-                         const char *merchant_id)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (merchant_id),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "purge_instance",
-                                             params);
-}
-
-
-/**
- * Update information about an instance into our database.
- *
- * @param cls closure
- * @param is details about the instance
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_instance (void *cls,
-                          const struct TALER_MERCHANTDB_InstanceSettings *is)
-{
-  struct PostgresClosure *pg = cls;
-  uint32_t ut32 = (uint32_t) is->ut;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (is->id),
-    GNUNET_PQ_query_param_string (is->name),
-    TALER_PQ_query_param_json (is->address),
-    TALER_PQ_query_param_json (is->jurisdiction),
-    TALER_PQ_query_param_amount (&is->default_max_deposit_fee),
-    TALER_PQ_query_param_amount (&is->default_max_wire_fee),
-    GNUNET_PQ_query_param_uint32 (&is->default_wire_fee_amortization),
-    GNUNET_PQ_query_param_relative_time (
-      &is->default_wire_transfer_delay),
-    GNUNET_PQ_query_param_relative_time (&is->default_pay_delay),
-    (NULL == is->website)
-    ? GNUNET_PQ_query_param_null ()
-    : GNUNET_PQ_query_param_string (is->website),
-    (NULL == is->email)
-    ? GNUNET_PQ_query_param_null ()
-    : GNUNET_PQ_query_param_string (is->email),
-    (NULL == is->logo)
-    ? GNUNET_PQ_query_param_null ()
-    : GNUNET_PQ_query_param_string (is->logo),
-    GNUNET_PQ_query_param_uint32 (&ut32),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "update_instance",
-                                             params);
-}
-
-
-/**
- * Update information about an instance's authentication settings
- * into our database.
- *
- * @param cls closure
- * @param merchant_id identity of the instance
- * @param is authentication details about the instance
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_instance_auth (
-  void *cls,
-  const char *merchant_id,
-  const struct TALER_MERCHANTDB_InstanceAuthSettings *is)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (merchant_id),
-    GNUNET_PQ_query_param_auto_from_type (&is->auth_hash),
-    GNUNET_PQ_query_param_auto_from_type (&is->auth_salt),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "update_instance_auth",
-                                             params);
-}
-
-
-/**
- * Set an instance's account in our database to "inactive".
- *
- * @param cls closure
- * @param merchant_id merchant backend instance ID
- * @param h_wire hash of the wire account to set to inactive
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_inactivate_account (void *cls,
-                             const char *merchant_id,
-                             const struct TALER_MerchantWireHashP *h_wire)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (merchant_id),
-    GNUNET_PQ_query_param_auto_from_type (h_wire),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "inactivate_account",
-                                             params);
-}
-
-
-/**
- * Set an instance's account in our database to "active".
- *
- * @param cls closure
- * @param merchant_id merchant backend instance ID
- * @param h_wire hash of the wire account to set to active
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_activate_account (void *cls,
-                           const char *merchant_id,
-                           const struct TALER_MerchantWireHashP *h_wire)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (merchant_id),
-    GNUNET_PQ_query_param_auto_from_type (h_wire),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "activate_account",
-                                             params);
-}
-
-
-/**
- * Context used for postgres_lookup_products().
- */
-struct LookupProductsContext
-{
-  /**
-   * Function to call with the results.
-   */
-  TALER_MERCHANTDB_ProductsCallback cb;
-
-  /**
-   * Closure for @a cb.
-   */
-  void *cb_cls;
-
-  /**
-   * Did database result extraction fail?
-   */
-  bool extract_failed;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about products.
- *
- * @param[in,out] cls of type `struct LookupProductsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_products_cb (void *cls,
-                    PGresult *result,
-                    unsigned int num_results)
-{
-  struct LookupProductsContext *plc = cls;
-
-  for (unsigned int i = 0; i < num_results; i++)
-  {
-    char *product_id;
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_string ("product_id",
-                                    &product_id),
-      GNUNET_PQ_result_spec_end
-    };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      plc->extract_failed = true;
-      return;
-    }
-    plc->cb (plc->cb_cls,
-             product_id);
-    GNUNET_PQ_cleanup_result (rs);
-  }
-}
-
-
-/**
- * Lookup all of the products the given instance has configured.
- *
- * @param cls closure
- * @param instance_id instance to lookup products for
- * @param cb function to call on all products found
- * @param cb_cls closure for @a cb
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_products (void *cls,
-                          const char *instance_id,
-                          TALER_MERCHANTDB_ProductsCallback cb,
-                          void *cb_cls)
-{
-  struct PostgresClosure *pg = cls;
-  struct LookupProductsContext plc = {
-    .cb = cb,
-    .cb_cls = cb_cls,
-    /* Can be overwritten by the lookup_products_cb */
-    .extract_failed = false,
-  };
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_end
-  };
-  enum GNUNET_DB_QueryStatus qs;
-
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                             "lookup_products",
-                                             params,
-                                             &lookup_products_cb,
-                                             &plc);
-  /* If there was an error inside lookup_products_cb, return a hard error. */
-  if (plc.extract_failed)
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  return qs;
-}
-
-
-/**
- * Lookup details about a particular product.
- *
- * @param cls closure
- * @param instance_id instance to lookup products for
- * @param product_id product to lookup
- * @param[out] pd set to the product details on success, can be NULL
- *             (in that case we only want to check if the product exists)
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_product (void *cls,
-                         const char *instance_id,
-                         const char *product_id,
-                         struct TALER_MERCHANTDB_ProductDetails *pd)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (product_id),
-    GNUNET_PQ_query_param_end
-  };
-
-  if (NULL == pd)
-  {
-    struct GNUNET_PQ_ResultSpec rs_null[] = {
-      GNUNET_PQ_result_spec_end
-    };
-
-    check_connection (pg);
-    return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                     "lookup_product",
-                                                     params,
-                                                     rs_null);
-  }
-  else
-  {
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_string ("description",
-                                    &pd->description),
-      TALER_PQ_result_spec_json ("description_i18n",
-                                 &pd->description_i18n),
-      GNUNET_PQ_result_spec_string ("unit",
-                                    &pd->unit),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("price",
-                                   &pd->price),
-      TALER_PQ_result_spec_json ("taxes",
-                                 &pd->taxes),
-      GNUNET_PQ_result_spec_uint64 ("total_stock",
-                                    &pd->total_stock),
-      GNUNET_PQ_result_spec_uint64 ("total_sold",
-                                    &pd->total_sold),
-      GNUNET_PQ_result_spec_uint64 ("total_lost",
-                                    &pd->total_lost),
-      GNUNET_PQ_result_spec_string ("image",
-                                    &pd->image),
-      TALER_PQ_result_spec_json ("address",
-                                 &pd->address),
-      GNUNET_PQ_result_spec_timestamp ("next_restock",
-                                       &pd->next_restock),
-      GNUNET_PQ_result_spec_uint32 ("minimum_age",
-                                    &pd->minimum_age),
-      GNUNET_PQ_result_spec_end
-    };
-
-    check_connection (pg);
-    return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                     "lookup_product",
-                                                     params,
-                                                     rs);
-  }
-}
-
-
-/**
- * Delete information about a product.  Note that the transaction must
- * enforce that no stocks are currently locked.
- *
- * @param cls closure
- * @param instance_id instance to delete product of
- * @param product_id product to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- *           if locks prevent deletion OR product unknown
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_product (void *cls,
-                         const char *instance_id,
-                         const char *product_id)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (product_id),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "delete_product",
-                                             params);
-}
-
-
-/**
- * Insert details about a particular product.
- *
- * @param cls closure
- * @param instance_id instance to insert product for
- * @param product_id product identifier of product to insert
- * @param pd the product details to insert
- * @return database result code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_product (void *cls,
-                         const char *instance_id,
-                         const char *product_id,
-                         const struct TALER_MERCHANTDB_ProductDetails *pd)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (product_id),
-    GNUNET_PQ_query_param_string (pd->description),
-    TALER_PQ_query_param_json (pd->description_i18n),
-    GNUNET_PQ_query_param_string (pd->unit),
-    GNUNET_PQ_query_param_string (pd->image),
-    TALER_PQ_query_param_json (pd->taxes),
-    TALER_PQ_query_param_amount (&pd->price),
-    GNUNET_PQ_query_param_uint64 (&pd->total_stock),
-    TALER_PQ_query_param_json (pd->address),
-    GNUNET_PQ_query_param_timestamp (&pd->next_restock),
-    GNUNET_PQ_query_param_uint32 (&pd->minimum_age),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_product",
-                                             params);
-}
-
-
-/**
- * Update details about a particular product. Note that the
- * transaction must enforce that the sold/stocked/lost counters
- * are not reduced (i.e. by expanding the WHERE clause on the existing
- * values).
- *
- * @param cls closure
- * @param instance_id instance to lookup products for
- * @param product_id product to lookup
- * @param[out] pd set to the product details on success, can be NULL
- *             (in that case we only want to check if the product exists)
- *             total_sold in @a pd is ignored, total_lost must not
- *             exceed total_stock minus the existing total_sold;
- *             total_sold and total_stock must be larger or equal to
- *             the existing value;
- * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the
- *         non-decreasing constraints are not met *or* if the product
- *         does not yet exist.
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_product (void *cls,
-                         const char *instance_id,
-                         const char *product_id,
-                         const struct TALER_MERCHANTDB_ProductDetails *pd)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id), /* $1 */
-    GNUNET_PQ_query_param_string (product_id),
-    GNUNET_PQ_query_param_string (pd->description),
-    TALER_PQ_query_param_json (pd->description_i18n),
-    GNUNET_PQ_query_param_string (pd->unit),
-    GNUNET_PQ_query_param_string (pd->image), /* $6 */
-    TALER_PQ_query_param_json (pd->taxes),
-    TALER_PQ_query_param_amount (&pd->price), /* $8+$9 */
-    GNUNET_PQ_query_param_uint64 (&pd->total_stock),  /* $10 */
-    GNUNET_PQ_query_param_uint64 (&pd->total_lost),
-    TALER_PQ_query_param_json (pd->address),
-    GNUNET_PQ_query_param_timestamp (&pd->next_restock),
-    GNUNET_PQ_query_param_uint32 (&pd->minimum_age),
-    GNUNET_PQ_query_param_end
-  };
-
-  if ( (pd->total_stock < pd->total_lost + pd->total_sold) ||
-       (pd->total_lost < pd->total_lost
-        + pd->total_sold) /* integer overflow */)
-  {
-    GNUNET_break (0);
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  }
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "update_product",
-                                             params);
-}
-
-
-/**
- * Lock stocks of a particular product. Note that the transaction must
- * enforce that the "stocked-sold-lost >= locked" constraint holds.
- *
- * @param cls closure
- * @param instance_id instance to lookup products for
- * @param product_id product to lookup
- * @param uuid the UUID that holds the lock
- * @param quantity how many units should be locked
- * @param expiration_time when should the lock expire
- * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the
- *         product is unknown OR if there insufficient stocks remaining
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lock_product (void *cls,
-                       const char *instance_id,
-                       const char *product_id,
-                       const struct GNUNET_Uuid *uuid,
-                       uint64_t quantity,
-                       struct GNUNET_TIME_Timestamp expiration_time)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (product_id),
-    GNUNET_PQ_query_param_auto_from_type (uuid),
-    GNUNET_PQ_query_param_uint64 (&quantity),
-    GNUNET_PQ_query_param_timestamp (&expiration_time),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "lock_product",
-                                             params);
-}
-
-
 /**
  * Release all expired product locks, including
  * those from expired offers -- across all
@@ -7027,252 +6206,6 @@ postgres_connect (void *cls)
   struct GNUNET_PQ_PreparedStatement ps[] = {
     GNUNET_PQ_make_prepare ("end_transaction",
                             "COMMIT"),
-    /* for call_with_accounts(), part of postgres_lookup_instances() */
-    GNUNET_PQ_make_prepare ("lookup_instance_auth",
-                            "SELECT"
-                            " auth_hash"
-                            ",auth_salt"
-                            " FROM merchant_instances"
-                            " WHERE merchant_id=$1"),
-    /* for postgres_insert_instance() */
-    GNUNET_PQ_make_prepare ("insert_instance",
-                            "INSERT INTO merchant_instances"
-                            "(merchant_pub"
-                            ",auth_hash"
-                            ",auth_salt"
-                            ",merchant_id"
-                            ",merchant_name"
-                            ",user_type"
-                            ",address"
-                            ",jurisdiction"
-                            ",default_max_deposit_fee_val"
-                            ",default_max_deposit_fee_frac"
-                            ",default_max_wire_fee_val"
-                            ",default_max_wire_fee_frac"
-                            ",default_wire_fee_amortization"
-                            ",default_wire_transfer_delay"
-                            ",default_pay_delay"
-                            ",website"
-                            ",email"
-                            ",logo)"
-                            "VALUES"
-                            "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, 
$12, $13, $14, $15, $16, $17, $18)"),
-    /* for postgres_insert_instance() */
-    GNUNET_PQ_make_prepare ("insert_keys",
-                            "INSERT INTO merchant_keys"
-                            "(merchant_priv"
-                            ",merchant_serial)"
-                            " SELECT $1, merchant_serial"
-                            " FROM merchant_instances"
-                            " WHERE merchant_id=$2"),
-    /* for postgres_account_kyc_set_status */
-    GNUNET_PQ_make_prepare ("upsert_account_kyc",
-                            "INSERT INTO merchant_kyc"
-                            "(kyc_timestamp"
-                            ",kyc_ok"
-                            ",exchange_kyc_serial"
-                            ",account_serial"
-                            ",exchange_url"
-                            ",exchange_pub"
-                            ",exchange_sig"
-                            ",aml_decision)"
-                            " SELECT $5, $6, $4, account_serial, $3, $7, $8, 
$9"
-                            " FROM merchant_instances"
-                            " JOIN merchant_accounts USING (merchant_serial)"
-                            " WHERE merchant_id=$1"
-                            "  AND h_wire=$2"
-                            " ON CONFLICT(account_serial,exchange_url) DO "
-                            "UPDATE"
-                            " SET exchange_kyc_serial=$4"
-                            "    ,kyc_timestamp=$5"
-                            "    ,kyc_ok=$6"
-                            "    ,exchange_pub=$7"
-                            "    ,exchange_sig=$8"
-                            "    ,aml_decision=$9"),
-    /* for postgres_account_kyc_get_status */
-    GNUNET_PQ_make_prepare ("lookup_kyc_status",
-                            "SELECT"
-                            " h_wire"
-                            ",exchange_kyc_serial"
-                            ",payto_uri"
-                            ",exchange_url"
-                            ",kyc_timestamp"
-                            ",kyc_ok"
-                            ",aml_decision"
-                            " FROM merchant_instances"
-                            " JOIN merchant_accounts"
-                            "   USING (merchant_serial)"
-                            " JOIN merchant_kyc"
-                            "   USING (account_serial)"
-                            " WHERE merchant_instances.merchant_id=$1"),
-    /* for postgres_delete_instance_private_key() */
-    GNUNET_PQ_make_prepare ("delete_key",
-                            "DELETE FROM merchant_keys"
-                            " USING merchant_instances"
-                            " WHERE merchant_keys.merchant_serial"
-                            "   = merchant_instances.merchant_serial"
-                            " AND merchant_instances.merchant_id = $1"),
-    /* for postgres_purge_instance() */
-    GNUNET_PQ_make_prepare ("purge_instance",
-                            "DELETE FROM merchant_instances"
-                            " WHERE merchant_instances.merchant_id = $1"),
-    /* for postgres_update_instance() */
-    GNUNET_PQ_make_prepare ("update_instance",
-                            "UPDATE merchant_instances SET"
-                            " merchant_name=$2"
-                            ",address=$3"
-                            ",jurisdiction=$4"
-                            ",default_max_deposit_fee_val=$5"
-                            ",default_max_deposit_fee_frac=$6"
-                            ",default_max_wire_fee_val=$7"
-                            ",default_max_wire_fee_frac=$8"
-                            ",default_wire_fee_amortization=$9"
-                            ",default_wire_transfer_delay=$10"
-                            ",default_pay_delay=$11"
-                            ",website=$12"
-                            ",email=$13"
-                            ",logo=$14"
-                            ",user_type=$15"
-                            " WHERE merchant_id=$1"),
-    /* for postgres_update_instance_auth() */
-    GNUNET_PQ_make_prepare ("update_instance_auth",
-                            "UPDATE merchant_instances SET"
-                            " auth_hash=$2"
-                            ",auth_salt=$3"
-                            " WHERE merchant_id=$1"),
-    /* for postgres_inactivate_account(); the merchant
-       instance is implied from the random salt that
-       is part of the h_wire calculation */
-    GNUNET_PQ_make_prepare ("inactivate_account",
-                            "UPDATE merchant_accounts SET"
-                            " active=FALSE"
-                            " WHERE h_wire=$2"
-                            "  AND merchant_serial="
-                            "   (SELECT merchant_serial"
-                            "      FROM merchant_instances"
-                            "      WHERE merchant_id=$1)"),
-    /* for postgres_activate_account() */
-    GNUNET_PQ_make_prepare ("activate_account",
-                            "UPDATE merchant_accounts SET"
-                            " active=TRUE"
-                            " WHERE h_wire=$2 AND"
-                            " merchant_serial="
-                            "   (SELECT merchant_serial"
-                            "      FROM merchant_instances"
-                            "      WHERE merchant_id=$1)"),
-    /* for postgres_lookup_products() */
-    GNUNET_PQ_make_prepare ("lookup_products",
-                            "SELECT"
-                            " product_id"
-                            " FROM merchant_inventory"
-                            " JOIN merchant_instances"
-                            "   USING (merchant_serial)"
-                            " WHERE merchant_instances.merchant_id=$1"),
-    /* for postgres_lookup_product() */
-    GNUNET_PQ_make_prepare ("lookup_product",
-                            "SELECT"
-                            " description"
-                            ",description_i18n"
-                            ",unit"
-                            ",price_val"
-                            ",price_frac"
-                            ",taxes"
-                            ",total_stock"
-                            ",total_sold"
-                            ",total_lost"
-                            ",image"
-                            ",merchant_inventory.address"
-                            ",next_restock"
-                            ",minimum_age"
-                            " FROM merchant_inventory"
-                            " JOIN merchant_instances"
-                            "   USING (merchant_serial)"
-                            " WHERE merchant_instances.merchant_id=$1"
-                            "   AND merchant_inventory.product_id=$2"),
-    /* for postgres_delete_product() */
-    GNUNET_PQ_make_prepare ("delete_product",
-                            "DELETE"
-                            " FROM merchant_inventory"
-                            " WHERE merchant_inventory.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND merchant_inventory.product_id=$2"
-                            "   AND product_serial NOT IN "
-                            "     (SELECT product_serial FROM 
merchant_order_locks)"
-                            "   AND product_serial NOT IN "
-                            "     (SELECT product_serial FROM 
merchant_inventory_locks)"),
-    /* for postgres_insert_product() */
-    GNUNET_PQ_make_prepare ("insert_product",
-                            "INSERT INTO merchant_inventory"
-                            "(merchant_serial"
-                            ",product_id"
-                            ",description"
-                            ",description_i18n"
-                            ",unit"
-                            ",image"
-                            ",taxes"
-                            ",price_val"
-                            ",price_frac"
-                            ",total_stock"
-                            ",address"
-                            ",next_restock"
-                            ",minimum_age"
-                            ")"
-                            " SELECT merchant_serial,"
-                            " $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, 
$13"
-                            " FROM merchant_instances"
-                            " WHERE merchant_id=$1"),
-    /* for postgres_update_product() */
-    GNUNET_PQ_make_prepare ("update_product",
-                            "UPDATE merchant_inventory SET"
-                            " description=$3"
-                            ",description_i18n=$4"
-                            ",unit=$5"
-                            ",image=$6"
-                            ",taxes=$7"
-                            ",price_val=$8"
-                            ",price_frac=$9"
-                            ",total_stock=$10"
-                            ",total_lost=$11"
-                            ",address=$12"
-                            ",next_restock=$13"
-                            ",minimum_age=$14"
-                            " WHERE merchant_serial="
-                            "   (SELECT merchant_serial"
-                            "      FROM merchant_instances"
-                            "      WHERE merchant_id=$1)"
-                            "   AND product_id=$2"
-                            "   AND total_stock <= $10"
-                            "   AND total_lost <= $11"),
-
-    /* for postgres_lock_product() */
-    GNUNET_PQ_make_prepare ("lock_product",
-                            "WITH ps AS"
-                            "  (SELECT product_serial"
-                            "   FROM merchant_inventory"
-                            "   WHERE product_id=$2"
-                            "     AND merchant_serial="
-                            "     (SELECT merchant_serial"
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1))"
-                            "INSERT INTO merchant_inventory_locks"
-                            "(product_serial"
-                            ",lock_uuid"
-                            ",total_locked"
-                            ",expiration)"
-                            " SELECT product_serial, $3, $4, $5"
-                            "   FROM merchant_inventory"
-                            "   JOIN ps USING (product_serial)"
-                            "   WHERE "
-                            "     total_stock - total_sold - total_lost - $4 
>= "
-                            "     (SELECT COALESCE(SUM(total_locked), 0)"
-                            "        FROM merchant_inventory_locks"
-                            "        WHERE product_serial=ps.product_serial) + 
"
-                            "     (SELECT COALESCE(SUM(total_locked), 0)"
-                            "        FROM merchant_order_locks"
-                            "        WHERE product_serial=ps.product_serial)"),
-
     /* for postgres_expire_locks() */
     GNUNET_PQ_make_prepare ("unlock_products",
                             "DELETE FROM merchant_inventory_locks"
@@ -9455,30 +8388,44 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
   plugin->start_read_committed = &postgres_start_read_committed;
   plugin->rollback = &postgres_rollback;
   plugin->commit = &postgres_commit;
-  plugin->lookup_instance_auth = &postgres_lookup_instance_auth;
-  plugin->insert_instance = &postgres_insert_instance;
+  plugin->lookup_instance_auth
+    = &TMH_PG_lookup_instance_auth;
+  plugin->insert_instance
+    = &TMH_PG_insert_instance;
   plugin->insert_account
     = &TMH_PG_insert_account;
   plugin->update_account
     = &TMH_PG_update_account;
   plugin->account_kyc_set_status
-    = &postgres_account_kyc_set_status;
+    = &TMH_PG_account_kyc_set_status;
   plugin->account_kyc_get_status
-    = &postgres_account_kyc_get_status;
-  plugin->delete_instance_private_key = &postgres_delete_instance_private_key;
-  plugin->purge_instance = &postgres_purge_instance;
-  plugin->update_instance = &postgres_update_instance;
-  plugin->update_instance_auth = &postgres_update_instance_auth;
-  plugin->activate_account = &postgres_activate_account;
-  plugin->inactivate_account = &postgres_inactivate_account;
+    = &TMH_PG_account_kyc_get_status;
+  plugin->delete_instance_private_key
+    = &TMH_PG_delete_instance_private_key;
+  plugin->purge_instance
+    = &TMH_PG_purge_instance;
+  plugin->update_instance
+    = &TMH_PG_update_instance;
+  plugin->update_instance_auth
+    = &TMH_PG_update_instance_auth;
+  plugin->activate_account
+    = &TMH_PG_activate_account;
+  plugin->inactivate_account
+    = &TMH_PG_inactivate_account;
   plugin->update_transfer_status
     = &TMH_PG_update_transfer_status;
-  plugin->lookup_products = &postgres_lookup_products;
-  plugin->lookup_product = &postgres_lookup_product;
-  plugin->delete_product = &postgres_delete_product;
-  plugin->insert_product = &postgres_insert_product;
-  plugin->update_product = &postgres_update_product;
-  plugin->lock_product = &postgres_lock_product;
+  plugin->lookup_products
+    = &TMH_PG_lookup_products;
+  plugin->lookup_product
+    = &TMH_PG_lookup_product;
+  plugin->delete_product
+    = &TMH_PG_delete_product;
+  plugin->insert_product
+    = &TMH_PG_insert_product;
+  plugin->update_product
+    = &TMH_PG_update_product;
+  plugin->lock_product
+    = &TMH_PG_lock_product;
   plugin->expire_locks = &postgres_expire_locks;
   plugin->delete_order = &postgres_delete_order;
   plugin->lookup_order = &postgres_lookup_order;

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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