diff options
Diffstat (limited to 'src/pq')
-rw-r--r-- | src/pq/db_pq.c | 48 | ||||
-rw-r--r-- | src/pq/pq_helper.c | 214 | ||||
-rw-r--r-- | src/pq/test_pq.c | 168 |
3 files changed, 364 insertions, 66 deletions
diff --git a/src/pq/db_pq.c b/src/pq/db_pq.c index 72a9370ed..a718c805f 100644 --- a/src/pq/db_pq.c +++ b/src/pq/db_pq.c @@ -60,6 +60,7 @@ TALER_PQ_exec_prepared (PGconn *db_conn, break; case TALER_PQ_QF_RSA_PUBLIC_KEY: case TALER_PQ_QF_RSA_SIGNATURE: + case TALER_PQ_QF_TIME_ABSOLUTE: len++; break; default: @@ -67,6 +68,7 @@ TALER_PQ_exec_prepared (PGconn *db_conn, GNUNET_assert (0); break; } + i++; } /* new scope to allow stack allocation without alloca */ @@ -111,7 +113,7 @@ TALER_PQ_exec_prepared (PGconn *db_conn, param_formats[off] = 1; off++; param_values[off] = (void *) amount->currency; - param_lengths[off] = strlen (amount->currency) + 1; + param_lengths[off] = strlen (amount->currency); param_formats[off] = 1; off++; } @@ -134,7 +136,7 @@ TALER_PQ_exec_prepared (PGconn *db_conn, param_formats[off] = 1; off++; param_values[off] = (void *) amount->currency; - param_lengths[off] = strlen (amount->currency) + 1; + param_lengths[off] = strlen (amount->currency); param_formats[off] = 1; off++; } @@ -176,8 +178,6 @@ TALER_PQ_exec_prepared (PGconn *db_conn, at_nbo = GNUNET_new (struct GNUNET_TIME_AbsoluteNBO); scratch[soff++] = at_nbo; - /* FIXME: this does not work for 'forever' as PQ uses 63-bit integers; - should check and handle! (Need testcase!) */ *at_nbo = GNUNET_TIME_absolute_hton (*at_hbo); param_values[off] = (void *) at_nbo; param_lengths[off] = sizeof (struct GNUNET_TIME_AbsoluteNBO); @@ -190,6 +190,7 @@ TALER_PQ_exec_prepared (PGconn *db_conn, GNUNET_assert (0); break; } + i++; } GNUNET_assert (off == len); res = PQexecPrepared (db_conn, @@ -200,7 +201,7 @@ TALER_PQ_exec_prepared (PGconn *db_conn, param_formats, 1); for (off = 0; off < soff; off++) - GNUNET_free (scratch[soff]); + GNUNET_free (scratch[off]); return res; } } @@ -222,25 +223,34 @@ TALER_PQ_cleanup_result (struct TALER_PQ_ResultSpec *rs) switch (rs[i].format) { case TALER_PQ_RF_VARSIZE_BLOB: - if (NULL != rs[i].dst) { - GNUNET_free (rs[i].dst); - rs[i].dst = NULL; - *rs[i].result_size = 0; + void **dst = rs[i].dst; + if (NULL != *dst) + { + GNUNET_free (*dst); + *dst = NULL; + *rs[i].result_size = 0; + } + break; } - break; case TALER_PQ_RF_RSA_PUBLIC_KEY: - if (NULL != rs[i].dst) { - GNUNET_CRYPTO_rsa_public_key_free (rs[i].dst); - rs[i].dst = NULL; + void **dst = rs[i].dst; + if (NULL != *dst) + { + GNUNET_CRYPTO_rsa_public_key_free (*dst); + *dst = NULL; + } + break; } - break; case TALER_PQ_RF_RSA_SIGNATURE: - if (NULL != rs[i].dst) { - GNUNET_CRYPTO_rsa_signature_free (rs[i].dst); - rs[i].dst = NULL; + void **dst = rs[i].dst; + if (NULL != *dst) + { + GNUNET_CRYPTO_rsa_signature_free (*dst); + *dst = NULL; + } } break; default: @@ -256,7 +266,7 @@ TALER_PQ_cleanup_result (struct TALER_PQ_ResultSpec *rs) * is returned. * * @param result result to process - * @param[in|out] rs result specification to extract for + * @param[in,out] rs result specification to extract for * @param row row from the result to extract * @return * #GNUNET_YES if all results could be extracted @@ -525,8 +535,6 @@ TALER_PQ_extract_result (PGresult *result, PQgetvalue (result, row, fnum); - /* FIXME: this does not work for 'forever' as PQ uses 63-bit integers; - should check and handle! (Need testcase!) */ *dst = GNUNET_TIME_absolute_ntoh (*res); break; } diff --git a/src/pq/pq_helper.c b/src/pq/pq_helper.c new file mode 100644 index 000000000..5da1ced41 --- /dev/null +++ b/src/pq/pq_helper.c @@ -0,0 +1,214 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors) + + 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, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file pq/pq_helper.c + * @brief functions to initialize parameter arrays + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "taler_pq_lib.h" + + +/** + * Generate query parameter for a currency, consisting of the three + * components "value", "fraction" and "currency" in this order. The + * types must be a 64-bit integer, 32-bit integer and a + * #TALER_CURRENCY_LEN-sized BLOB/VARCHAR respectively. + * + * @param x pointer to the query parameter to pass + * @return array entry for the query parameters to use + */ +struct TALER_PQ_QueryParam +TALER_PQ_query_param_amount_nbo (const struct TALER_AmountNBO *x) +{ + struct TALER_PQ_QueryParam res = + { TALER_PQ_QF_AMOUNT_NBO, x, sizeof (*x) }; + return res; +} + + +/** + * Generate query parameter for a currency, consisting of the three + * components "value", "fraction" and "currency" in this order. The + * types must be a 64-bit integer, 32-bit integer and a + * #TALER_CURRENCY_LEN-sized BLOB/VARCHAR respectively. + * + * @param x pointer to the query parameter to pass + * @return array entry for the query parameters to use + */ +struct TALER_PQ_QueryParam +TALER_PQ_query_param_amount (const struct TALER_Amount *x) +{ + struct TALER_PQ_QueryParam res = + { TALER_PQ_QF_AMOUNT, x, sizeof (*x) }; + return res; +} + + +/** + * Generate query parameter for an RSA public key. The + * database must contain a BLOB type in the respective position. + * + * @param x the query parameter to pass + * @return array entry for the query parameters to use + */ +struct TALER_PQ_QueryParam +TALER_PQ_query_param_rsa_public_key (const struct GNUNET_CRYPTO_rsa_PublicKey *x) +{ + struct TALER_PQ_QueryParam res = + { TALER_PQ_QF_RSA_PUBLIC_KEY, (x), 0 }; + return res; +} + + +/** + * Generate query parameter for an RSA signature. The + * database must contain a BLOB type in the respective position. + * + * @param x the query parameter to pass + * @return array entry for the query parameters to use + */ +struct TALER_PQ_QueryParam +TALER_PQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_rsa_Signature *x) +{ + struct TALER_PQ_QueryParam res = + { TALER_PQ_QF_RSA_SIGNATURE, (x), 0 }; + return res; +} + + +/** + * Generate query parameter for an absolute time value. + * The database must store a 64-bit integer. + * + * @param x pointer to the query parameter to pass + * @return array entry for the query parameters to use + */ +struct TALER_PQ_QueryParam +TALER_PQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x) +{ + struct TALER_PQ_QueryParam res = + { TALER_PQ_QF_TIME_ABSOLUTE, x, sizeof (*x) }; + return res; +} + + +/** + * Variable-size result expected. + * + * @param name name of the field in the table + * @param[out] dst where to store the result, allocated + * @param[out] sptr where to store the size of @a dst + * @return array entry for the result specification to use + */ +struct TALER_PQ_ResultSpec +TALER_PQ_result_spec_variable_size (const char *name, + void **dst, + size_t *sptr) +{ + struct TALER_PQ_ResultSpec res = + { TALER_PQ_RF_VARSIZE_BLOB, (void *) (dst), 0, name, sptr }; + return res; +} + + +/** + * Currency amount expected. + * + * @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 TALER_PQ_ResultSpec +TALER_PQ_result_spec_amount_nbo (const char *name, + struct TALER_AmountNBO *amount) +{ + struct TALER_PQ_ResultSpec res = + {TALER_PQ_RF_AMOUNT_NBO, (void *) amount, sizeof (*amount), name, NULL }; + return res; +} + + +/** + * Currency amount expected. + * + * @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 TALER_PQ_ResultSpec +TALER_PQ_result_spec_amount (const char *name, + struct TALER_Amount *amount) +{ + struct TALER_PQ_ResultSpec res = + {TALER_PQ_RF_AMOUNT, (void *) amount, sizeof (*amount), name, NULL }; + return res; +} + + +/** + * RSA public key expected. + * + * @param name name of the field in the table + * @param[out] rsa where to store the result + * @return array entry for the result specification to use + */ +struct TALER_PQ_ResultSpec +TALER_PQ_result_spec_rsa_public_key (const char *name, + struct GNUNET_CRYPTO_rsa_PublicKey **rsa) +{ + struct TALER_PQ_ResultSpec res = + {TALER_PQ_RF_RSA_PUBLIC_KEY, (void *) rsa, 0, name, NULL }; + return res; +} + + +/** + * RSA signature expected. + * + * @param name name of the field in the table + * @param[out] sig where to store the result; + * @return array entry for the result specification to use + */ +struct TALER_PQ_ResultSpec +TALER_PQ_result_spec_rsa_signature (const char *name, + struct GNUNET_CRYPTO_rsa_Signature **sig) +{ + struct TALER_PQ_ResultSpec res = + {TALER_PQ_RF_RSA_SIGNATURE, (void *) sig, 0, (name), NULL }; + return res; +} + + +/** + * Absolute time expected. + * + * @param name name of the field in the table + * @param[out] at where to store the result + * @return array entry for the result specification to use + */ +struct TALER_PQ_ResultSpec +TALER_PQ_result_spec_absolute_time (const char *name, + struct GNUNET_TIME_Absolute *at) +{ + struct TALER_PQ_ResultSpec res = + {TALER_PQ_RF_TIME_ABSOLUTE, (void *) at, sizeof (*at), (name), NULL }; + return res; +} + + +/* end of pq_helper.c */ diff --git a/src/pq/test_pq.c b/src/pq/test_pq.c index 2d56e11e7..ff89e29f3 100644 --- a/src/pq/test_pq.c +++ b/src/pq/test_pq.c @@ -60,9 +60,10 @@ postgres_prepare (PGconn *db_conn) ",namount_val" ",namount_frac" ",namount_curr" + ",vsize" ") VALUES " "($1, $2, $3, $4, $5, $6," - "$7, $8, $9, $10, $11);", + "$7, $8, $9, $10, $11, $12);", 11, NULL); PREPARE ("test_select", "SELECT" @@ -77,9 +78,10 @@ postgres_prepare (PGconn *db_conn) ",namount_val" ",namount_frac" ",namount_curr" - "FROM test_pq" - "ORDER BY abs_time DESC " - "LIMIT 1;", + ",vsize" + " FROM test_pq" + " ORDER BY abs_time DESC " + " LIMIT 1;", 0, NULL); return GNUNET_OK; #undef PREPARE @@ -108,47 +110,119 @@ run_queries (PGconn *conn) struct TALER_Amount hamount2; struct TALER_AmountNBO namount; struct TALER_AmountNBO namount2; - struct TALER_PQ_QueryParam params_insert[] = { - TALER_PQ_QUERY_PARAM_RSA_PUBLIC_KEY (pub), - TALER_PQ_QUERY_PARAM_RSA_SIGNATURE (sig), - TALER_PQ_QUERY_PARAM_ABSOLUTE_TIME (abs_time), - TALER_PQ_QUERY_PARAM_ABSOLUTE_TIME (forever), - TALER_PQ_QUERY_PARAM_PTR (&hc), - TALER_PQ_QUERY_PARAM_AMOUNT (hamount), - TALER_PQ_QUERY_PARAM_AMOUNT_NBO (namount), - TALER_PQ_QUERY_PARAM_END - }; - struct TALER_PQ_QueryParam params_select[] = { - TALER_PQ_QUERY_PARAM_END - }; - struct TALER_PQ_ResultSpec results_select[] = { - TALER_PQ_RESULT_SPEC_RSA_PUBLIC_KEY ("pub", pub2), - TALER_PQ_RESULT_SPEC_RSA_SIGNATURE ("sig", sig2), - TALER_PQ_RESULT_SPEC_ABSOLUTE_TIME ("abs_time", abs_time2), - TALER_PQ_RESULT_SPEC_ABSOLUTE_TIME ("forever", forever2), - TALER_PQ_RESULT_SPEC ("hash", &hc2), - TALER_PQ_RESULT_SPEC_AMOUNT ("hamount", hamount2), - TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("namount", namount2), - TALER_PQ_RESULT_SPEC_END - }; PGresult *result; int ret; + struct GNUNET_CRYPTO_rsa_PrivateKey *priv; + char msg[] = "Hello"; + void *msg2; + size_t msg2_len; + + priv = GNUNET_CRYPTO_rsa_private_key_create (1024); + pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv); + sig = GNUNET_CRYPTO_rsa_sign (priv, + msg, + sizeof (msg)); + TALER_string_to_amount ("EUR:5.5", + &hamount); + TALER_amount_hton (&namount, + &hamount); + TALER_string_to_amount ("EUR:4.4", + &hamount); + /* FIXME: test TALER_PQ_result_spec_variable_size */ + { + struct TALER_PQ_QueryParam params_insert[] = { + TALER_PQ_query_param_rsa_public_key (pub), + TALER_PQ_query_param_rsa_signature (sig), + TALER_PQ_query_param_absolute_time (&abs_time), + TALER_PQ_query_param_absolute_time (&forever), + TALER_PQ_query_param_auto_from_type (&hc), + TALER_PQ_query_param_amount (&hamount), + TALER_PQ_query_param_amount_nbo (&namount), + TALER_PQ_query_param_fixed_size (msg, strlen (msg)), + TALER_PQ_query_param_end + }; + struct TALER_PQ_QueryParam params_select[] = { + TALER_PQ_query_param_end + }; + struct TALER_PQ_ResultSpec results_select[] = { + TALER_PQ_result_spec_rsa_public_key ("pub", &pub2), + TALER_PQ_result_spec_rsa_signature ("sig", &sig2), + TALER_PQ_result_spec_absolute_time ("abs_time", &abs_time2), + TALER_PQ_result_spec_absolute_time ("forever", &forever2), + TALER_PQ_result_spec_auto_from_type ("hash", &hc2), + TALER_PQ_result_spec_amount ("hamount", &hamount2), + TALER_PQ_result_spec_amount_nbo ("namount", &namount2), + TALER_PQ_result_spec_variable_size ("vsize", &msg2, &msg2_len), + TALER_PQ_result_spec_end + }; + + result = TALER_PQ_exec_prepared (conn, + "test_insert", + params_insert); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Database failure: %s\n", + PQresultErrorMessage (result)); + PQclear (result); + GNUNET_CRYPTO_rsa_signature_free (sig); + GNUNET_CRYPTO_rsa_private_key_free (priv); + GNUNET_CRYPTO_rsa_public_key_free (pub); + return 1; + } + + PQclear (result); + result = TALER_PQ_exec_prepared (conn, + "test_select", + params_select); + if (1 != + PQntuples (result)) + { + GNUNET_break (0); + PQclear (result); + GNUNET_CRYPTO_rsa_signature_free (sig); + GNUNET_CRYPTO_rsa_private_key_free (priv); + GNUNET_CRYPTO_rsa_public_key_free (pub); + return 1; + } + ret = TALER_PQ_extract_result (result, + results_select, + 0); + GNUNET_break (GNUNET_YES == ret); + GNUNET_break (abs_time.abs_value_us == abs_time2.abs_value_us); + GNUNET_break (forever.abs_value_us == forever2.abs_value_us); + GNUNET_break (0 == + memcmp (&hc, + &hc2, + sizeof (struct GNUNET_HashCode))); + GNUNET_break (0 == + TALER_amount_cmp (&hamount, + &hamount2)); + TALER_string_to_amount ("EUR:5.5", + &hamount); + TALER_amount_ntoh (&hamount2, + &namount2); + GNUNET_break (0 == + TALER_amount_cmp (&hamount, + &hamount2)); + GNUNET_break (0 == + GNUNET_CRYPTO_rsa_signature_cmp (sig, + sig2)); + GNUNET_break (0 == + GNUNET_CRYPTO_rsa_public_key_cmp (pub, + pub2)); + GNUNET_break (strlen (msg) == msg2_len); + GNUNET_break (0 == + strncmp (msg, + msg2, + msg2_len)); - // FIXME: init pub, sig - result = TALER_PQ_exec_prepared (conn, - "test_insert", - params_insert); - PQclear (result); - result = TALER_PQ_exec_prepared (conn, - "test_select", - params_select); - ret = TALER_PQ_extract_result (result, - results_select, - 0); - // FIXME: cmp results! - TALER_PQ_cleanup_result (results_select); - PQclear (result); - + TALER_PQ_cleanup_result (results_select); + PQclear (result); + } + GNUNET_CRYPTO_rsa_signature_free (sig); + GNUNET_CRYPTO_rsa_private_key_free (priv); + GNUNET_CRYPTO_rsa_public_key_free (pub); if (GNUNET_OK != ret) return 1; @@ -164,8 +238,10 @@ main(int argc, PGresult *result; int ret; - // FIXME: pass valid connect string for tests... - conn = PQconnectdb (""); + GNUNET_log_setup ("test-pq", + "WARNING", + NULL); + conn = PQconnectdb ("postgres:///talercheck"); if (CONNECTION_OK != PQstatus (conn)) { fprintf (stderr, @@ -177,7 +253,7 @@ main(int argc, } result = PQexec (conn, - "CREATE TABLE test_pq (" + "CREATE TEMPORARY TABLE IF NOT EXISTS test_pq (" " pub BYTEA NOT NULL" ",sig BYTEA NOT NULL" ",abs_time INT8 NOT NULL" @@ -189,6 +265,7 @@ main(int argc, ",namount_val INT8 NOT NULL" ",namount_frac INT4 NOT NULL" ",namount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",vsize VARCHAR NOT NULL" ")"); if (PGRES_COMMAND_OK != PQresultStatus (result)) { @@ -204,7 +281,6 @@ main(int argc, postgres_prepare (conn)) { GNUNET_break (0); - PQclear (result); PQfinish (conn); return 1; } |