gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] branch master updated: extend libtalerpq with functions


From: gnunet
Subject: [taler-exchange] branch master updated: extend libtalerpq with functions for the amount with currency triplet data type (for merchant backend)
Date: Mon, 21 Aug 2023 21:07:23 +0200

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

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new d1e242aa extend libtalerpq with functions for the amount with currency 
triplet data type (for merchant backend)
d1e242aa is described below

commit d1e242aa083cd108aca6e3ceda5f3459c8cebdc4
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Mon Aug 21 21:07:18 2023 +0200

    extend libtalerpq with functions for the amount with currency triplet data 
type (for merchant backend)
---
 src/include/taler_pq_lib.h |  36 +++++++++-
 src/pq/Makefile.am         |   2 +-
 src/pq/pq_common.c         |  65 ++++++++++++++++++
 src/pq/pq_common.h         |  73 ++++++++++++++++----
 src/pq/pq_query_helper.c   | 121 +++++++++++++++++++++++++++++----
 src/pq/pq_result_helper.c  | 163 ++++++++++++++++++++++++++++++++++++++++++---
 6 files changed, 425 insertions(+), 35 deletions(-)

diff --git a/src/include/taler_pq_lib.h b/src/include/taler_pq_lib.h
index 25b5f868..21e48792 100644
--- a/src/include/taler_pq_lib.h
+++ b/src/include/taler_pq_lib.h
@@ -45,6 +45,22 @@ TALER_PQ_query_param_amount (
   const struct GNUNET_PQ_Context *db,
   const struct TALER_Amount *amount);
 
+
+/**
+ * Generate query parameter (as record tuple) for an amount, consisting of the
+ * three components "value", "fraction" and "currency" in this order. The
+ * types must be a 64-bit integer, a 32-bit integer and a TEXT field of 12
+ * characters respectively.
+ *
+ * @param db The database context for OID lookup
+ * @param amount pointer to the query parameter to pass
+ */
+struct GNUNET_PQ_QueryParam
+TALER_PQ_query_param_amount_with_currency (
+  const struct GNUNET_PQ_Context *db,
+  const struct TALER_Amount *amount);
+
+
 /**
  * Generate query parameter for a denomination public
  * key. Internally, the various attributes of the
@@ -161,7 +177,24 @@ TALER_PQ_query_param_array_amount (
 
 
 /**
- * Currency amount expected, from a record-field of (DB) taler_amount type
+ * Currency amount expected, from a record-field of (DB)
+ * taler_amount_with_currency type. The currenty must be stored in the
+ * database when using this function.
+ *
+ * @param name name of the field in the table
+ * @param[out] amount where to store the result
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+TALER_PQ_result_spec_amount_with_currency (
+  const char *name,
+  struct TALER_Amount *amount);
+
+
+/**
+ * Currency amount expected, from a record-field of (DB) taler_amount type.
+ * The currency is NOT stored in the database when using this function, but
+ * instead passed as the @a currency argument.
  *
  * @param name name of the field in the table
  * @param currency currency to use for @a amount
@@ -173,6 +206,7 @@ TALER_PQ_result_spec_amount (const char *name,
                              const char *currency,
                              struct TALER_Amount *amount);
 
+
 /**
  * Denomination public key expected.
  *
diff --git a/src/pq/Makefile.am b/src/pq/Makefile.am
index c1c9e9bb..4b192d76 100644
--- a/src/pq/Makefile.am
+++ b/src/pq/Makefile.am
@@ -10,7 +10,7 @@ lib_LTLIBRARIES = \
   libtalerpq.la
 
 libtalerpq_la_SOURCES = \
-  pq_common.h \
+  pq_common.h pq_common.c \
   pq_query_helper.c \
   pq_result_helper.c
 libtalerpq_la_LIBADD = \
diff --git a/src/pq/pq_common.c b/src/pq/pq_common.c
new file mode 100644
index 00000000..a548a45c
--- /dev/null
+++ b/src/pq/pq_common.c
@@ -0,0 +1,65 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2023 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 pq/pq_common.c
+ * @brief common defines for the pq functions
+ * @author Özgür Kesim
+ */
+#include "platform.h"
+#include "pq_common.h"
+
+struct TALER_PQ_AmountP
+TALER_PQ_make_taler_pq_amount_ (
+  const struct TALER_Amount *amount,
+  uint32_t oid_v,
+  uint32_t oid_f)
+{
+  struct TALER_PQ_AmountP rval = {
+    .oid_v = htonl (oid_v),
+    .oid_f = htonl (oid_f),
+    .sz_v = htonl (sizeof((amount)->value)),
+    .sz_f = htonl (sizeof((amount)->fraction)),
+    .v = GNUNET_htonll ((amount)->value),
+    .f = htonl ((amount)->fraction)
+  };
+
+  return rval;
+}
+
+
+struct TALER_PQ_AmountCurrencyP
+TALER_PQ_make_taler_pq_amount_currency_ (
+  const struct TALER_Amount *amount,
+  uint32_t oid_v,
+  uint32_t oid_f,
+  uint32_t oid_c)
+{
+  struct TALER_PQ_AmountCurrencyP rval = {
+    .oid_v = htonl (oid_v),
+    .oid_f = htonl (oid_f),
+    .oid_c = htonl (oid_c),
+    .sz_v = htonl (sizeof((amount)->value)),
+    .sz_f = htonl (sizeof((amount)->fraction)),
+    .sz_c = htonl (TALER_CURRENCY_LEN),
+    .v = GNUNET_htonll ((amount)->value),
+    .f = htonl ((amount)->fraction),
+  };
+
+  memcpy (rval.c,
+          amount->currency,
+          TALER_CURRENCY_LEN);
+  return rval;
+}
diff --git a/src/pq/pq_common.h b/src/pq/pq_common.h
index d479ce5b..4dc2d335 100644
--- a/src/pq/pq_common.h
+++ b/src/pq/pq_common.h
@@ -21,7 +21,8 @@
 #ifndef TALER_PQ_COMMON_H_
 #define TALER_PQ_COMMON_H_
 
-#include "platform.h"
+#include "taler_util.h"
+
 /**
  * Internal types that are supported as TALER-exchange-specific array types.
  *
@@ -43,6 +44,9 @@ enum TALER_PQ_ArrayType
   TALER_PQ_array_of_blinded_denom_sig,
   TALER_PQ_array_of_blinded_coin_hash,
   TALER_PQ_array_of_denom_hash,
+  /**
+   * Amounts *without* currency.
+   */
   TALER_PQ_array_of_amount,
   TALER_PQ_array_of_MAX,       /* must be last */
 };
@@ -52,7 +56,7 @@ enum TALER_PQ_ArrayType
  *
  * All values need to be in network-byte-order.
  */
-struct TALER_PQ_Amount_P
+struct TALER_PQ_AmountP
 {
   uint32_t oid_v; /* oid of .v  */
   uint32_t sz_v;  /* size of .v */
@@ -62,23 +66,66 @@ struct TALER_PQ_Amount_P
   uint32_t f;     /* fraction   */
 } __attribute__((packed));
 
+
+/**
+ * Memory representation of an taler amount record with currency for Postgres.
+ *
+ * All values need to be in network-byte-order.
+ */
+struct TALER_PQ_AmountCurrencyP
+{
+  uint32_t oid_v; /* oid of .v  */
+  uint32_t sz_v;  /* size of .v */
+  uint64_t v;     /* value      */
+  uint32_t oid_f; /* oid of .f  */
+  uint32_t sz_f;  /* size of .f */
+  uint32_t f;     /* fraction   */
+
+  /**
+   * oid of .c
+   */
+  uint32_t oid_c;
+
+  /**
+   * size of .c
+   */
+  uint32_t sz_c;
+
+  /**
+   * currency
+   */
+  uint8_t c[TALER_CURRENCY_LEN];
+} __attribute__((packed));
+
+
+/**
+ * Create a `struct TALER_PQ_AmountP` for initialization
+ *
+ * @param amount amount of type `struct TALER_Amount *`
+ * @param oid_v OID of the INT8 type in postgres
+ * @param oid_f OID of the INT4 type in postgres
+ */
+struct TALER_PQ_AmountP
+TALER_PQ_make_taler_pq_amount_ (
+  const struct TALER_Amount *amount,
+  uint32_t oid_v,
+  uint32_t oid_f);
+
+
 /**
- * Create a `struct TALER_PQ_Amount_P` for initialization
+ * Create a `struct TALER_PQ_AmountCurrencyP` for initialization
  *
- * @param db postgres-context of type `struct GNUNET_PQ_Context *`
  * @param amount amount of type `struct TALER_Amount *`
  * @param oid_v OID of the INT8 type in postgres
  * @param oid_f OID of the INT4 type in postgres
+ * @param oid_c OID of the TEXT type in postgres
  */
-#define MAKE_TALER_PQ_AMOUNT_P(db,amount,oid_v,oid_f) \
-  { \
-    .oid_v = htonl (oid_v), \
-    .oid_f = htonl (oid_f), \
-    .sz_v = htonl (sizeof((amount)->value)), \
-    .sz_f = htonl (sizeof((amount)->fraction)), \
-    .v = GNUNET_htonll ((amount)->value), \
-    .f = htonl ((amount)->fraction) \
-  }
+struct TALER_PQ_AmountCurrencyP
+TALER_PQ_make_taler_pq_amount_currency_ (
+  const struct TALER_Amount *amount,
+  uint32_t oid_v,
+  uint32_t oid_f,
+  uint32_t oid_c);
 
 
 #endif  /* TALER_PQ_COMMON_H_ */
diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c
index 78f29d64..a1a1070b 100644
--- a/src/pq/pq_query_helper.c
+++ b/src/pq/pq_query_helper.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016, 2021, 2022 Taler Systems SA
+  Copyright (C) 2014-2023 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
@@ -28,6 +28,102 @@
 #include "pq_common.h"
 
 
+/**
+ * Function called to convert input amount into SQL parameter as tuple.
+ *
+ * @param cls closure
+ * @param data pointer to input argument, here a `struct TALER_Amount`
+ * @param data_len number of bytes in @a data (if applicable)
+ * @param[out] param_values SQL data to set
+ * @param[out] param_lengths SQL length data to set
+ * @param[out] param_formats SQL format data to set
+ * @param param_length number of entries available in the @a param_values, @a 
param_lengths and @a param_formats arrays
+ * @param[out] scratch buffer for dynamic allocations (to be done via 
GNUNET_malloc()
+ * @param scratch_length number of entries left in @a scratch
+ * @return -1 on error, number of offsets used in @a scratch otherwise
+ */
+static int
+qconv_amount_currency_tuple (void *cls,
+                             const void *data,
+                             size_t data_len,
+                             void *param_values[],
+                             int param_lengths[],
+                             int param_formats[],
+                             unsigned int param_length,
+                             void *scratch[],
+                             unsigned int scratch_length)
+{
+  struct GNUNET_PQ_Context *db = cls;
+  const struct TALER_Amount *amount = data;
+  size_t sz;
+
+  GNUNET_assert (NULL != db);
+  GNUNET_assert (NULL != amount);
+  GNUNET_assert (1 == param_length);
+  GNUNET_assert (1 <= scratch_length);
+  GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
+  GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid));
+  {
+    char *out;
+    Oid oid_v;
+    Oid oid_f;
+    Oid oid_c;
+
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_PQ_get_oid_by_name (db,
+                                              "int8",
+                                              &oid_v));
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_PQ_get_oid_by_name (db,
+                                              "int4",
+                                              &oid_f));
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_PQ_get_oid_by_name (db,
+                                              "text",
+                                              &oid_c));
+
+    {
+      struct TALER_PQ_AmountCurrencyP d
+        = TALER_PQ_make_taler_pq_amount_currency_ (amount,
+                                                   oid_v,
+                                                   oid_f,
+                                                   oid_c);
+
+      sz = sizeof(uint32_t); /* number of elements in tuple */
+      sz += sizeof(d);
+      out = GNUNET_malloc (sz);
+      scratch[0] = out;
+      *(uint32_t *) out = htonl (3);
+      out += sizeof(uint32_t);
+      *(struct TALER_PQ_AmountCurrencyP*) out = d;
+    }
+  }
+
+  param_values[0] = scratch[0];
+  param_lengths[0] = sz;
+  param_formats[0] = 1;
+
+  return 1;
+}
+
+
+struct GNUNET_PQ_QueryParam
+TALER_PQ_query_param_amount_with_currency (
+  const struct GNUNET_PQ_Context *db,
+  const struct TALER_Amount *amount)
+{
+  struct GNUNET_PQ_QueryParam res = {
+    .conv_cls = (void *) db,
+    .conv = &qconv_amount_currency_tuple,
+    .data = amount,
+    .size = sizeof (*amount),
+    .num_params = 1,
+  };
+
+  return res;
+}
+
+
 /**
  * Function called to convert input amount into SQL parameter as tuple.
  *
@@ -78,18 +174,18 @@ qconv_amount_tuple (void *cls,
                                               &oid_f));
 
     {
-      struct TALER_PQ_Amount_P d
-        = MAKE_TALER_PQ_AMOUNT_P (db,
-                                  amount,
-                                  oid_v,
-                                  oid_f);
+      struct TALER_PQ_AmountP d
+        = TALER_PQ_make_taler_pq_amount_ (amount,
+                                          oid_v,
+                                          oid_f);
+
       sz = sizeof(uint32_t); /* number of elements in tuple */
       sz += sizeof(d);
       out = GNUNET_malloc (sz);
       scratch[0] = out;
       *(uint32_t *) out = htonl (2);
       out += sizeof(uint32_t);
-      *(struct TALER_PQ_Amount_P*) out = d;
+      *(struct TALER_PQ_AmountP*) out = d;
     }
   }
 
@@ -872,10 +968,11 @@ qconv_array (
                                                     "int4",
                                                     &oid_f));
           {
-            struct TALER_PQ_Amount_P am = MAKE_TALER_PQ_AMOUNT_P (meta->db,
-                                                                  &amounts[i],
-                                                                  oid_v,
-                                                                  oid_f);
+            struct TALER_PQ_AmountP am
+              = TALER_PQ_make_taler_pq_amount_ (
+                  &amounts[i],
+                  oid_v,
+                  oid_f);
 
             *(uint32_t *) out = htonl (2); /* number of elements in tuple */
             out += sizeof(uint32_t);
@@ -1086,7 +1183,7 @@ TALER_PQ_query_param_array_amount (
     true,
     amounts,
     NULL,
-    sizeof(uint32_t) + sizeof(struct TALER_PQ_Amount_P),
+    sizeof(uint32_t) + sizeof(struct TALER_PQ_AmountP),
     TALER_PQ_array_of_amount,
     oid,
     db);
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
index d4810c9a..3befbdff 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -24,6 +24,151 @@
 #include "taler_pq_lib.h"
 
 
+/**
+ * Extract an amount from a tuple including the currency from a Postgres
+ * database @a result at row @a row.
+ *
+ * @param cls closure; not used
+ * @param result where to extract data from
+ * @param row row to extract data from
+ * @param fname name (or prefix) of the fields to extract from
+ * @param[in,out] dst_size where to store size of result, may be NULL
+ * @param[out] dst where to store the result
+ * @return
+ *   #GNUNET_YES if all results could be extracted
+ *   #GNUNET_NO if at least one result was NULL
+ *   #GNUNET_SYSERR if a result was invalid (non-existing field)
+ */
+static enum GNUNET_GenericReturnValue
+extract_amount_currency_tuple (void *cls,
+                               PGresult *result,
+                               int row,
+                               const char *fname,
+                               size_t *dst_size,
+                               void *dst)
+{
+  struct TALER_Amount *r_amount = dst;
+  int col;
+
+  (void) cls;
+  if (sizeof (struct TALER_Amount) != *dst_size)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* Set return value to invalid in case we don't finish */
+  memset (r_amount,
+          0,
+          sizeof (struct TALER_Amount));
+  col = PQfnumber (result,
+                   fname);
+  if (col < 0)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Field `%s' does not exist in result\n",
+                fname);
+    return GNUNET_SYSERR;
+  }
+  if (PQgetisnull (result,
+                   row,
+                   col))
+  {
+    return GNUNET_NO;
+  }
+
+  /* Parse the tuple */
+  {
+    char *in;
+    uint32_t num;
+    struct TALER_PQ_AmountCurrencyP ap;
+    int size;
+    const static int expected_size
+      = sizeof(uint32_t) /* length */
+        + sizeof(ap);
+
+    size = PQgetlength (result,
+                        row,
+                        col);
+    if (expected_size != size)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Incorrect size of binary field `%s' (got %d, expected 
%d)\n",
+                  fname,
+                  size,
+                  expected_size);
+      return GNUNET_SYSERR;
+    }
+
+    in = PQgetvalue (result,
+                     row,
+                     col);
+
+    num = ntohl (*(uint32_t *) in);
+    if (3 != num)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Incorrect number of elements in tuple-field `%s'\n",
+                  fname);
+      return GNUNET_SYSERR;
+    }
+    in += sizeof(uint32_t);
+    memcpy (&ap,
+            in,
+            sizeof (ap));
+    /* TODO[oec]: OID-checks? */
+
+    r_amount->value = GNUNET_ntohll (ap.v);
+    r_amount->fraction = ntohl (ap.f);
+    memcpy (r_amount->currency,
+            ap.c,
+            TALER_CURRENCY_LEN);
+    if ('\0' != r_amount->currency[TALER_CURRENCY_LEN - 1])
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Invalid currency (not 0-terminated) in tuple field `%s'\n",
+                  fname);
+      /* be sure nobody uses this by accident */
+      memset (r_amount,
+              0,
+              sizeof (struct TALER_Amount));
+      return GNUNET_SYSERR;
+    }
+  }
+
+  if (r_amount->value >= TALER_AMOUNT_MAX_VALUE)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Value in field `%s' exceeds legal range\n",
+                fname);
+    return GNUNET_SYSERR;
+  }
+  if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Fraction in field `%s' exceeds legal range\n",
+                fname);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+TALER_PQ_result_spec_amount_with_currency (const char *name,
+                                           struct TALER_Amount *amount)
+{
+  struct GNUNET_PQ_ResultSpec res = {
+    .conv = &extract_amount_currency_tuple,
+    .dst = (void *) amount,
+    .dst_size = sizeof (*amount),
+    .fname = name
+  };
+
+  return res;
+}
+
+
 /**
  * Extract an amount from a tuple from a Postgres database @a result at row @a 
row.
  *
@@ -49,7 +194,7 @@ extract_amount_tuple (void *cls,
   struct TALER_Amount *r_amount = dst;
   const char *currency = cls;
   int col;
-  int len;
+  size_t len;
 
   if (sizeof (struct TALER_Amount) != *dst_size)
   {
@@ -81,10 +226,10 @@ extract_amount_tuple (void *cls,
   {
     char *in;
     uint32_t num;
-    struct TALER_PQ_Amount_P ap;
+    struct TALER_PQ_AmountP ap;
     int size;
     const static int expected_size = sizeof(uint32_t) /* length */
-                                     + sizeof(struct TALER_PQ_Amount_P);
+                                     + sizeof(ap);
 
     size = PQgetlength (result,
                         row,
@@ -113,7 +258,9 @@ extract_amount_tuple (void *cls,
       return GNUNET_SYSERR;
     }
     in += sizeof(uint32_t);
-    ap = *(struct TALER_PQ_Amount_P *) in;
+    memcpy (&ap,
+            in,
+            sizeof (ap));
 
     /* TODO[oec]: OID-checks? */
 
@@ -993,14 +1140,14 @@ extract_array_generic (
 
         for (uint32_t i = 0; i < header.dim; i++)
         {
-          struct TALER_PQ_Amount_P ap;
+          struct TALER_PQ_AmountP ap;
           struct TALER_Amount *amount = &amounts[i];
           size_t sz = ntohl (*(uint32_t *) in);
           in += sizeof(uint32_t);
 
           /* total size for this array-entry */
           FAIL_IF ((sizeof(uint32_t)
-                    + sizeof(struct TALER_PQ_Amount_P))
+                    + sizeof(struct TALER_PQ_AmountP))
                    > sz);
 
           /* number of elements in composite type*/
@@ -1008,14 +1155,14 @@ extract_array_generic (
           in += sizeof(uint32_t);
           FAIL_IF (2 != sz);
 
-          ap = *(struct TALER_PQ_Amount_P *) in;
+          ap = *(struct TALER_PQ_AmountP *) in;
           amount->value = GNUNET_ntohll (ap.v);
           amount->fraction = ntohl (ap.f);
           GNUNET_memcpy (amount->currency,
                          info->currency,
                          TALER_CURRENCY_LEN);
 
-          in += sizeof(struct TALER_PQ_Amount_P);
+          in += sizeof(struct TALER_PQ_AmountP);
         }
         return GNUNET_OK;
       }

-- 
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]