aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/taler_pq_lib.h36
-rw-r--r--src/pq/Makefile.am2
-rw-r--r--src/pq/pq_common.c65
-rw-r--r--src/pq/pq_common.h73
-rw-r--r--src/pq/pq_query_helper.c121
-rw-r--r--src/pq/pq_result_helper.c163
6 files changed, 425 insertions, 35 deletions
diff --git a/src/include/taler_pq_lib.h b/src/include/taler_pq_lib.h
index 25b5f8688..21e48792c 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 c1c9e9bb0..4b192d762 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 000000000..a548a45ca
--- /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 d479ce5bb..4dc2d3357 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 78f29d643..a1a1070bb 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
@@ -43,6 +43,102 @@
* @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.
+ *
+ * @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_tuple (void *cls,
const void *data,
size_t data_len,
@@ -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 d4810c9ad..3befbdff1 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -25,6 +25,151 @@
/**
+ * 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.
*
* @param cls closure, a `const char *` giving the currency
@@ -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;
}