aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2023-07-29 21:26:58 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2023-07-29 21:26:58 +0200
commitecf6b2750bb6ed9157aece72602dd042a50e36f3 (patch)
treef4436d80f00a07ac8e7193ee6e33c70d1b3a8424 /src
parent28d80d3b38531eddfd37b2a8bcff9f209cf522ac (diff)
[pq] added array support for taler_amount composite type
API added: - TALER_PQ_query_param_array_amount - TALER_PQ_result_spec_array_amount
Diffstat (limited to 'src')
-rw-r--r--src/include/taler_pq_lib.h32
-rw-r--r--src/pq/pq_common.h2
-rw-r--r--src/pq/pq_query_helper.c65
-rw-r--r--src/pq/pq_result_helper.c82
-rw-r--r--src/pq/test_pq.c57
5 files changed, 226 insertions, 12 deletions
diff --git a/src/include/taler_pq_lib.h b/src/include/taler_pq_lib.h
index 051962b2b..fddfd2a29 100644
--- a/src/include/taler_pq_lib.h
+++ b/src/include/taler_pq_lib.h
@@ -194,6 +194,19 @@ TALER_PQ_query_param_array_blinded_coin_hash (
const struct GNUNET_PQ_Context *db);
/**
+ * Generate query parameter for an array of mounts
+ *
+ * @param num of elements in @e amounts
+ * @param amounts continuous array of amounts
+ * @param db context for db-connection, needed for OID-lookup
+ */
+struct GNUNET_PQ_QueryParam
+TALER_PQ_query_param_array_amount (
+ size_t num,
+ const struct TALER_Amount *amounts,
+ struct GNUNET_PQ_Context *db);
+
+/**
* Currency amount expected.
*
* @param name name of the field in the table
@@ -356,6 +369,25 @@ TALER_PQ_result_spec_array_denom_hash (
size_t *num,
struct TALER_DenominationHashP **denom_hs);
+/**
+ * Array of amounts
+ *
+ * @param db context of the database connection
+ * @param name name of the field in the table
+ * @param currency The currency
+ * @param[out] num number of elements in @e amounts
+ * @param[out] amounts where to store the result
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+TALER_PQ_result_spec_array_amount (
+ struct GNUNET_PQ_Context *db, /* not const because we need to query dynamically */
+ const char *name,
+ const char *currency,
+ size_t *num,
+ struct TALER_Amount **amounts);
+
+
#endif /* TALER_PQ_LIB_H_ */
/* end of include/taler_pq_lib.h */
diff --git a/src/pq/pq_common.h b/src/pq/pq_common.h
index 79c9d83ca..26137f422 100644
--- a/src/pq/pq_common.h
+++ b/src/pq/pq_common.h
@@ -43,7 +43,7 @@ enum TALER_PQ_ArrayType
TALER_PQ_array_of_blinded_denom_sig,
TALER_PQ_array_of_blinded_coin_hash,
TALER_PQ_array_of_denom_hash,
- /* TODO[oec]: Next up: TALER_PQ_array_of_amount, */
+ TALER_PQ_array_of_amount,
TALER_PQ_array_of_MAX, /* must be last */
};
diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c
index 6d8318b41..a21b0b1d0 100644
--- a/src/pq/pq_query_helper.c
+++ b/src/pq/pq_query_helper.c
@@ -791,6 +791,11 @@ struct qconv_array_cls
* Oid of the array elements
*/
Oid oid;
+
+ /**
+ * db context, needed for OID-lookup of basis-types
+ */
+ const struct GNUNET_PQ_Context *db;
};
/**
@@ -964,6 +969,20 @@ qconv_array (
switch (meta->typ)
{
+ case TALER_PQ_array_of_amount:
+ {
+ const struct TALER_Amount *amounts = data;
+ struct TALER_PQ_Amount_P am = MAKE_TALER_PQ_AMOUNT_P (meta->db,
+ &amounts[i]);
+
+ *(uint32_t *) out = htonl (2); /* number of elements in tuple */
+ out += sizeof(uint32_t);
+ sz -= sizeof(uint32_t);
+ GNUNET_memcpy (out,
+ &am,
+ sizeof(am));
+ break;
+ }
case TALER_PQ_array_of_blinded_denom_sig:
{
const struct TALER_BlindedDenominationSignature *denom_sigs = data;
@@ -1066,7 +1085,8 @@ query_param_array_generic (
const size_t *sizes,
size_t same_size,
enum TALER_PQ_ArrayType typ,
- Oid oid)
+ Oid oid,
+ const struct GNUNET_PQ_Context *db)
{
struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls);
meta->typ = typ;
@@ -1074,6 +1094,7 @@ query_param_array_generic (
meta->sizes = sizes;
meta->same_size = same_size;
meta->continuous = continuous;
+ meta->db = db;
struct GNUNET_PQ_QueryParam res = {
.conv = qconv_array,
@@ -1101,8 +1122,10 @@ TALER_PQ_query_param_array_blinded_denom_sig (
0,
TALER_PQ_array_of_blinded_denom_sig,
GNUNET_PQ_get_oid (db,
- GNUNET_PQ_DATATYPE_BYTEA));
-};
+ GNUNET_PQ_DATATYPE_BYTEA),
+ NULL);
+}
+
struct GNUNET_PQ_QueryParam
TALER_PQ_query_param_array_blinded_coin_hash (
@@ -1117,8 +1140,10 @@ TALER_PQ_query_param_array_blinded_coin_hash (
sizeof(struct TALER_BlindedCoinHashP),
TALER_PQ_array_of_blinded_coin_hash,
GNUNET_PQ_get_oid (db,
- GNUNET_PQ_DATATYPE_BYTEA));
-};
+ GNUNET_PQ_DATATYPE_BYTEA),
+ NULL);
+}
+
struct GNUNET_PQ_QueryParam
TALER_PQ_query_param_array_denom_hash (
@@ -1133,6 +1158,32 @@ TALER_PQ_query_param_array_denom_hash (
sizeof(struct TALER_DenominationHashP),
TALER_PQ_array_of_denom_hash,
GNUNET_PQ_get_oid (db,
- GNUNET_PQ_DATATYPE_BYTEA));
-};
+ GNUNET_PQ_DATATYPE_BYTEA),
+ NULL);
+}
+
+
+struct GNUNET_PQ_QueryParam
+TALER_PQ_query_param_array_amount (
+ size_t num,
+ const struct TALER_Amount *amounts,
+ struct GNUNET_PQ_Context *db)
+{
+ if (TALER_PQ_CompositeOIDs[0] == 0)
+ GNUNET_assert (GNUNET_OK ==
+ TALER_PQ_load_oids_for_composite_types (db));
+
+ return query_param_array_generic (
+ num,
+ true,
+ amounts,
+ NULL,
+ sizeof(uint32_t) /* the # of elements in the tuple, here: 2 */
+ + sizeof(struct TALER_PQ_Amount_P),
+ TALER_PQ_array_of_amount,
+ TALER_PQ_CompositeOIDs[TALER_PQ_CompositeAmount],
+ db);
+}
+
+
/* end of pq/pq_query_helper.c */
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
index ac1642bae..52e42562d 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -1136,6 +1136,12 @@ struct ArrayResultCls
/* Out-pointer. If @a typ is TALER_PQ_array_of_byte and @a same_size is 0,
* allocate and put the array of @a num sizes here. NULL otherwise */
size_t **sizes;
+
+ /* DB_connection, needed for OID-lookup for composite types */
+ const struct GNUNET_PQ_Context *db;
+
+ /* Currency information for amount composites */
+ char currency[TALER_CURRENCY_LEN];
};
/**
@@ -1216,6 +1222,43 @@ extract_array_generic (
switch (info->typ)
{
+ case TALER_PQ_array_of_amount:
+ {
+ struct TALER_Amount *amounts;
+ if (NULL != dst_size)
+ *dst_size = sizeof(struct TALER_Amount) * (header.dim);
+
+ amounts = GNUNET_new_array (header.dim, struct TALER_Amount);
+ *((void **) dst) = amounts;
+
+ for (uint32_t i = 0; i < header.dim; i++)
+ {
+ struct TALER_PQ_Amount_P 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))
+ > sz);
+
+ /* number of elements in composite type*/
+ sz = ntohl (*(uint32_t *) in);
+ in += sizeof(uint32_t);
+ FAIL_IF (2 != sz);
+
+ ap = *(struct TALER_PQ_Amount_P *) 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);
+ }
+ return GNUNET_OK;
+ }
case TALER_PQ_array_of_denom_hash:
if (NULL != dst_size)
*dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim);
@@ -1415,5 +1458,44 @@ TALER_PQ_result_spec_array_denom_hash (
};
+struct GNUNET_PQ_ResultSpec
+TALER_PQ_result_spec_array_amount (
+ struct GNUNET_PQ_Context *db,
+ const char *name,
+ const char *currency,
+ size_t *num,
+ struct TALER_Amount **amounts)
+{
+ if (TALER_PQ_CompositeOIDs[0] == 0)
+ GNUNET_assert (GNUNET_OK ==
+ TALER_PQ_load_oids_for_composite_types (db));
+
+ struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
+
+ info->num = num;
+ info->typ = TALER_PQ_array_of_amount;
+ info->oid = TALER_PQ_CompositeOIDs[TALER_PQ_CompositeAmount];
+ info->db = db;
+
+ {
+ size_t clen = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
+ strlen (currency));
+ GNUNET_memcpy (&info->currency,
+ currency,
+ clen);
+ }
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) amounts,
+ .fname = name,
+ .cls = info,
+ };
+ return res;
+
+
+}
+
/* end of pq_result_helper.c */
diff --git a/src/pq/test_pq.c b/src/pq/test_pq.c
index 9f18e7675..a09e500f5 100644
--- a/src/pq/test_pq.c
+++ b/src/pq/test_pq.c
@@ -35,20 +35,24 @@ postgres_prepare (struct GNUNET_PQ_Context *db)
struct GNUNET_PQ_PreparedStatement ps[] = {
GNUNET_PQ_make_prepare ("test_insert",
"INSERT INTO test_pq ("
- " hamount_val"
+ " tamount"
+ ",hamount_val"
",hamount_frac"
",namount_val"
",namount_frac"
",json"
+ ",aamount"
") VALUES "
- "($1, $2, $3, $4, $5);"),
+ "($1, $2, $3, $4, $5, $6, $7);"),
GNUNET_PQ_make_prepare ("test_select",
"SELECT"
- " hamount_val"
+ " tamount"
+ ",hamount_val"
",hamount_frac"
",namount_val"
",namount_frac"
",json"
+ ",aamount"
" FROM test_pq;"),
GNUNET_PQ_PREPARED_STATEMENT_END
};
@@ -66,16 +70,32 @@ postgres_prepare (struct GNUNET_PQ_Context *db)
static int
run_queries (struct GNUNET_PQ_Context *conn)
{
+ struct TALER_Amount tamount;
struct TALER_Amount hamount;
struct TALER_Amount hamount2;
struct TALER_AmountNBO namount;
struct TALER_AmountNBO namount2;
+ struct TALER_Amount aamount[3];
+ struct TALER_Amount *pamount;
+ size_t npamount;
PGresult *result;
int ret;
json_t *json;
json_t *json2;
GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:5.3",
+ &aamount[0]));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:6.4",
+ &aamount[1]));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:7.5",
+ &aamount[2]));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:7.7",
+ &tamount));
+ GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("EUR:5.5",
&hamount));
TALER_amount_hton (&namount,
@@ -88,9 +108,13 @@ run_queries (struct GNUNET_PQ_Context *conn)
GNUNET_assert (NULL != json);
{
struct GNUNET_PQ_QueryParam params_insert[] = {
+ TALER_PQ_query_param_amount_tuple (conn, &tamount),
TALER_PQ_query_param_amount (&hamount),
TALER_PQ_query_param_amount_nbo (&namount),
TALER_PQ_query_param_json (json),
+ TALER_PQ_query_param_array_amount (3,
+ aamount,
+ conn),
GNUNET_PQ_query_param_end
};
@@ -129,6 +153,12 @@ run_queries (struct GNUNET_PQ_Context *conn)
TALER_PQ_result_spec_amount ("hamount", "EUR", &hamount2),
TALER_PQ_result_spec_amount_nbo ("namount", "EUR", &namount2),
TALER_PQ_result_spec_json ("json", &json2),
+ TALER_PQ_result_spec_amount_tuple ("tamount", "EUR", &tamount),
+ TALER_PQ_result_spec_array_amount (conn,
+ "aamount",
+ "EUR",
+ &npamount,
+ &pamount),
GNUNET_PQ_result_spec_end
};
@@ -148,6 +178,15 @@ run_queries (struct GNUNET_PQ_Context *conn)
&hamount2));
GNUNET_break (42 ==
json_integer_value (json_object_get (json2, "foo")));
+
+ GNUNET_break (3 == npamount);
+ for (size_t i = 0; i < 3; i++)
+ {
+ GNUNET_break (0 ==
+ TALER_amount_cmp (&aamount[i],
+ &pamount[i]));
+ }
+
GNUNET_PQ_cleanup_result (results_select);
PQclear (result);
}
@@ -164,12 +203,22 @@ main (int argc,
const char *const argv[])
{
struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_execute ("DO $$ "
+ " BEGIN"
+ " CREATE TYPE taler_amount AS"
+ " (val INT8, frac INT4);"
+ " EXCEPTION"
+ " WHEN duplicate_object THEN null;"
+ " END "
+ "$$;"),
GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq ("
- " hamount_val INT8 NOT NULL"
+ " tamount taler_amount NOT NULL"
+ ",hamount_val INT8 NOT NULL"
",hamount_frac INT4 NOT NULL"
",namount_val INT8 NOT NULL"
",namount_frac INT4 NOT NULL"
",json VARCHAR NOT NULL"
+ ",aamount taler_amount[]"
")"),
GNUNET_PQ_EXECUTE_STATEMENT_END
};