diff options
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 |
commit | 571d43cef3732ed6f491d91a9e767a80008edeb1 (patch) | |
tree | b330d46d7698a07c4cc9c8baf1d2ee7793a4f02a /src/pq | |
parent | 722e00b1e9869e0ff337d40b28f2ed71d8afcd76 (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.c | 83 | ||||
-rw-r--r-- | src/pq/pq_result_helper.c | 145 |
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); |