aboutsummaryrefslogtreecommitdiff
path: root/src/pq
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2023-07-27 23:57:07 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2023-07-27 23:57:07 +0200
commit571d43cef3732ed6f491d91a9e767a80008edeb1 (patch)
treeb330d46d7698a07c4cc9c8baf1d2ee7793a4f02a /src/pq
parent722e00b1e9869e0ff337d40b28f2ed71d8afcd76 (diff)
[WiP] added TALER_AMOUNT type to Postgres - first in age_withdraw
- Added a type TALER_AMOUNT (val INT8, frac INT4) to Postgres. - Added PLSQL functions/procedures - amount_normalize(a) - amount_add(a, b) - amount_left_minus_right(l, r, diff, ok bool) - Added PQ-helper functions - TALER_PQ_query_param_amount_tuple() - TALER_PQ_result_spec_amount_tuple() - In table 'age_withdraw', changed fields 'amount_with_fee_val' and '..._frac' into single field 'amount_with_fee' be of type TALER_AMOUNT - Changed functions/stored procedures 'do_age_withdraw' and 'get_age_withdraw' to use new APIs. => make check runs through without errors, age-withdraw and -reveal test passes.
Diffstat (limited to 'src/pq')
-rw-r--r--src/pq/pq_query_helper.c83
-rw-r--r--src/pq/pq_result_helper.c145
2 files changed, 223 insertions, 5 deletions
diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c
index 9a02cddab..9ada23575 100644
--- a/src/pq/pq_query_helper.c
+++ b/src/pq/pq_query_helper.c
@@ -21,6 +21,7 @@
* @author Christian Grothoff
*/
#include "platform.h"
+#include <gnunet/gnunet_common.h>
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_pq_lib.h>
#include "taler_pq_lib.h"
@@ -150,6 +151,84 @@ TALER_PQ_query_param_amount (const struct TALER_Amount *x)
/**
+ * 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,
+ void *param_values[],
+ int param_lengths[],
+ int param_formats[],
+ unsigned int param_length,
+ void *scratch[],
+ unsigned int scratch_length)
+{
+ const 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;
+ struct TALER_PQ_Amount_P d = MAKE_TALER_PQ_AMOUNT_P (db, amount);
+
+ 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;
+
+ }
+
+ param_values[0] = scratch[0];
+ param_lengths[0] = sz;
+ param_formats[0] = 1;
+
+ return 1;
+}
+
+
+struct GNUNET_PQ_QueryParam
+TALER_PQ_query_param_amount_tuple (
+ const struct GNUNET_PQ_Context *db,
+ const struct TALER_Amount *amount)
+{
+ struct GNUNET_PQ_QueryParam res = {
+ .conv_cls = (void *) db,
+ .conv = &qconv_amount_tuple,
+ .data = amount,
+ .size = sizeof (*amount),
+ .num_params = 1,
+ };
+
+ return res;
+}
+
+
+/**
* Function called to convert input argument into SQL parameters.
*
* @param cls closure
@@ -793,7 +872,7 @@ qconv_array (
RETURN_UNLESS ((0 == num) || (y / num == x));
/* size of header */
- total_size = x = sizeof(struct TALER_PQ_ArrayHeader);
+ total_size = x = sizeof(struct TALER_PQ_ArrayHeader_P);
total_size += y;
RETURN_UNLESS (total_size >= x);
@@ -862,7 +941,7 @@ qconv_array (
/* Write data */
{
char *out = elements;
- struct TALER_PQ_ArrayHeader h = {
+ struct TALER_PQ_ArrayHeader_P h = {
.ndim = htonl (1), /* We only support one-dimensional arrays */
.has_null = htonl (0), /* We do not support NULL entries in arrays */
.lbound = htonl (1), /* Default start index value */
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
index 0a734bbc9..3ef2e71fb 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -265,6 +265,145 @@ TALER_PQ_result_spec_amount (const char *name,
/**
+ * 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
+ * @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_tuple (void *cls,
+ PGresult *result,
+ int row,
+ const char *fname,
+ size_t *dst_size,
+ void *dst)
+{
+ struct TALER_Amount *r_amount = dst;
+ const char *currency = cls;
+ int col;
+ int len;
+
+ 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_Amount_P ap;
+ int size;
+ const static int expected_size = sizeof(uint32_t) /* length */
+ + sizeof(struct TALER_PQ_Amount_P);
+
+ 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 (2 != num)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Incorrect number of elements in tuple-field `%s'\n",
+ fname);
+ return GNUNET_SYSERR;
+ }
+ in += sizeof(uint32_t);
+ ap = *(struct TALER_PQ_Amount_P *) in;
+
+ /* TODO[oec]: OID-checks? */
+
+ r_amount->value = GNUNET_ntohll (ap.v);
+ r_amount->fraction = ntohl (ap.f);
+ }
+
+ 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;
+ }
+
+ len = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
+ strlen (currency));
+
+ GNUNET_memcpy (r_amount->currency,
+ currency,
+ len);
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+TALER_PQ_result_spec_amount_tuple (const char *name,
+ const char *currency,
+ struct TALER_Amount *amount)
+{
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = &extract_amount_tuple,
+ .cls = (void *) currency,
+ .dst = (void *) amount,
+ .dst_size = sizeof (*amount),
+ .fname = name
+ };
+
+ return res;
+}
+
+
+/**
* Extract data from a Postgres database @a result at row @a row.
*
* @param cls closure
@@ -1027,7 +1166,7 @@ extract_array_generic (
int data_sz;
char *data;
void *out = NULL;
- struct TALER_PQ_ArrayHeader header;
+ struct TALER_PQ_ArrayHeader_P header;
int col_num;
GNUNET_assert (NULL != dst);
@@ -1053,8 +1192,8 @@ extract_array_generic (
FAIL_IF (NULL == data);
{
- struct TALER_PQ_ArrayHeader *h =
- (struct TALER_PQ_ArrayHeader *) data;
+ struct TALER_PQ_ArrayHeader_P *h =
+ (struct TALER_PQ_ArrayHeader_P *) data;
header.ndim = ntohl (h->ndim);
header.has_null = ntohl (h->has_null);