From ecf6b2750bb6ed9157aece72602dd042a50e36f3 Mon Sep 17 00:00:00 2001 From: Özgür Kesim Date: Sat, 29 Jul 2023 21:26:58 +0200 Subject: [pq] added array support for taler_amount composite type API added: - TALER_PQ_query_param_array_amount - TALER_PQ_result_spec_array_amount --- src/pq/pq_common.h | 2 +- src/pq/pq_query_helper.c | 65 +++++++++++++++++++++++++++++++++---- src/pq/pq_result_helper.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++ src/pq/test_pq.c | 57 +++++++++++++++++++++++++++++--- 4 files changed, 194 insertions(+), 12 deletions(-) (limited to 'src/pq') 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,15 +70,31 @@ 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)); @@ -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 }; -- cgit v1.2.3