diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-02-06 17:39:18 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-02-06 17:39:18 +0100 |
commit | 2b5a7c8748405fd8f28c840c3142e5ff35f2fa36 (patch) | |
tree | 24d23d53d4adf915815a557c97831a7e3caeb602 /src/pq | |
parent | a396f4e7fa39f17aec35360eb12098629649c831 (diff) |
move to new libgnunetpq library, simplifying libtalerpq
Diffstat (limited to 'src/pq')
-rw-r--r-- | src/pq/Makefile.am | 8 | ||||
-rw-r--r-- | src/pq/db_pq.c | 883 | ||||
-rw-r--r-- | src/pq/pq_helper.c | 370 | ||||
-rw-r--r-- | src/pq/pq_query_helper.c | 208 | ||||
-rw-r--r-- | src/pq/pq_result_helper.c | 358 | ||||
-rw-r--r-- | src/pq/test_pq.c | 153 |
6 files changed, 595 insertions, 1385 deletions
diff --git a/src/pq/Makefile.am b/src/pq/Makefile.am index 2187d494b..810aa47b3 100644 --- a/src/pq/Makefile.am +++ b/src/pq/Makefile.am @@ -12,8 +12,8 @@ lib_LTLIBRARIES = \ libtalerpq.la libtalerpq_la_SOURCES = \ - db_pq.c \ - pq_helper.c + pq_query_helper.c \ + pq_result_helper.c libtalerpq_la_LIBADD = \ $(top_builddir)/src/util/libtalerutil.la \ @@ -36,5 +36,7 @@ test_pq_SOURCES = \ test_pq_LDADD = \ libtalerpq.la \ $(top_builddir)/src/util/libtalerutil.la \ - -lgnunetutil -ljansson \ + -lgnunetpq \ + -lgnunetutil \ + -ljansson \ -lpq $(XLIB) diff --git a/src/pq/db_pq.c b/src/pq/db_pq.c deleted file mode 100644 index 59a1db022..000000000 --- a/src/pq/db_pq.c +++ /dev/null @@ -1,883 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - 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/db_pq.c - * @brief helper functions for libpq (PostGres) interactions - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Florian Dold - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include "taler_pq_lib.h" - - -/** - * Execute a prepared statement. - * - * @param db_conn database connection - * @param name name of the prepared statement - * @param params parameters to the statement - * @return postgres result - */ -PGresult * -TALER_PQ_exec_prepared (PGconn *db_conn, - const char *name, - const struct TALER_PQ_QueryParam *params) -{ - unsigned int len; - unsigned int i; - - /* count the number of parameters */ - i = 0; - len = 0; - while (TALER_PQ_QF_END != params[i].format) - { - const struct TALER_PQ_QueryParam *x = ¶ms[i]; - - switch (x->format) - { - case TALER_PQ_QF_FIXED_BLOB: - case TALER_PQ_QF_VARSIZE_BLOB: - len++; - break; - case TALER_PQ_QF_AMOUNT_NBO: - case TALER_PQ_QF_AMOUNT: - len += 3; - break; - case TALER_PQ_QF_RSA_PUBLIC_KEY: - case TALER_PQ_QF_RSA_SIGNATURE: - case TALER_PQ_QF_TIME_ABSOLUTE: - case TALER_PQ_QF_UINT16: - case TALER_PQ_QF_UINT32: - case TALER_PQ_QF_UINT64: - case TALER_PQ_QF_JSON: - len++; - break; - default: - /* format not supported */ - GNUNET_assert (0); - break; - } - i++; - } - - /* new scope to allow stack allocation without alloca */ - { - /* Scratch buffer for temporary storage */ - void *scratch[len]; - /* Parameter array we are building for the query */ - void *param_values[len]; - int param_lengths[len]; - int param_formats[len]; - unsigned int off; - /* How many entries in the scratch buffer are in use? */ - unsigned int soff; - PGresult *res; - - i = 0; - off = 0; - soff = 0; - while (TALER_PQ_QF_END != params[i].format) - { - const struct TALER_PQ_QueryParam *x = ¶ms[i]; - - switch (x->format) - { - case TALER_PQ_QF_FIXED_BLOB: - case TALER_PQ_QF_VARSIZE_BLOB: - param_values[off] = (void *) x->data; - param_lengths[off] = x->size; - param_formats[off] = 1; - off++; - break; - case TALER_PQ_QF_AMOUNT_NBO: - { - const struct TALER_Amount *amount = x->data; - - param_values[off] = (void *) &amount->value; - param_lengths[off] = sizeof (amount->value); - param_formats[off] = 1; - off++; - param_values[off] = (void *) &amount->fraction; - param_lengths[off] = sizeof (amount->fraction); - param_formats[off] = 1; - off++; - param_values[off] = (void *) amount->currency; - param_lengths[off] = strlen (amount->currency); - param_formats[off] = 1; - off++; - } - break; - case TALER_PQ_QF_AMOUNT: - { - const struct TALER_Amount *amount_hbo = x->data; - struct TALER_AmountNBO *amount; - - amount = GNUNET_new (struct TALER_AmountNBO); - scratch[soff++] = amount; - TALER_amount_hton (amount, - amount_hbo); - param_values[off] = (void *) &amount->value; - param_lengths[off] = sizeof (amount->value); - param_formats[off] = 1; - off++; - param_values[off] = (void *) &amount->fraction; - param_lengths[off] = sizeof (amount->fraction); - param_formats[off] = 1; - off++; - param_values[off] = (void *) amount->currency; - param_lengths[off] = strlen (amount->currency); - param_formats[off] = 1; - off++; - } - break; - case TALER_PQ_QF_RSA_PUBLIC_KEY: - { - const struct GNUNET_CRYPTO_rsa_PublicKey *rsa = x->data; - char *buf; - size_t buf_size; - - buf_size = GNUNET_CRYPTO_rsa_public_key_encode (rsa, - &buf); - scratch[soff++] = buf; - param_values[off] = (void *) buf; - param_lengths[off] = buf_size - 1; /* DB doesn't like the trailing \0 */ - param_formats[off] = 1; - off++; - } - break; - case TALER_PQ_QF_RSA_SIGNATURE: - { - const struct GNUNET_CRYPTO_rsa_Signature *sig = x->data; - char *buf; - size_t buf_size; - - buf_size = GNUNET_CRYPTO_rsa_signature_encode (sig, - &buf); - scratch[soff++] = buf; - param_values[off] = (void *) buf; - param_lengths[off] = buf_size - 1; /* DB doesn't like the trailing \0 */ - param_formats[off] = 1; - off++; - } - break; - case TALER_PQ_QF_TIME_ABSOLUTE: - { - const struct GNUNET_TIME_Absolute *at_hbo = x->data; - struct GNUNET_TIME_AbsoluteNBO *at_nbo; - - at_nbo = GNUNET_new (struct GNUNET_TIME_AbsoluteNBO); - scratch[soff++] = at_nbo; - *at_nbo = GNUNET_TIME_absolute_hton (*at_hbo); - param_values[off] = (void *) at_nbo; - param_lengths[off] = sizeof (struct GNUNET_TIME_AbsoluteNBO); - param_formats[off] = 1; - off++; - } - break; - case TALER_PQ_QF_UINT16: - { - const uint16_t *u_hbo = x->data; - uint16_t *u_nbo; - - u_nbo = GNUNET_new (uint16_t); - scratch[soff++] = u_nbo; - *u_nbo = htons (*u_hbo); - param_values[off] = (void *) u_nbo; - param_lengths[off] = sizeof (uint16_t); - param_formats[off] = 1; - off++; - } - break; - case TALER_PQ_QF_UINT32: - { - const uint32_t *u_hbo = x->data; - uint32_t *u_nbo; - - u_nbo = GNUNET_new (uint32_t); - scratch[soff++] = u_nbo; - *u_nbo = htonl (*u_hbo); - param_values[off] = (void *) u_nbo; - param_lengths[off] = sizeof (uint32_t); - param_formats[off] = 1; - off++; - } - break; - case TALER_PQ_QF_UINT64: - { - const uint64_t *u_hbo = x->data; - uint64_t *u_nbo; - - u_nbo = GNUNET_new (uint64_t); - scratch[soff++] = u_nbo; - *u_nbo = GNUNET_htonll (*u_hbo); - param_values[off] = (void *) u_nbo; - param_lengths[off] = sizeof (uint64_t); - param_formats[off] = 1; - off++; - } - break; - case TALER_PQ_QF_JSON: - { - const json_t *json = x->data; - char *str; - - str = json_dumps (json, JSON_COMPACT); - GNUNET_assert (NULL != str); - scratch[soff++] = str; - param_values[off] = (void *) str; - param_lengths[off] = strlen (str); - param_formats[off] = 1; - off++; - } - break; - default: - /* format not supported */ - GNUNET_assert (0); - break; - } - i++; - } - GNUNET_assert (off == len); - res = PQexecPrepared (db_conn, - name, - len, - (const char **) param_values, - param_lengths, - param_formats, - 1); - for (off = 0; off < soff; off++) - GNUNET_free (scratch[off]); - return res; - } -} - - -/** - * Free all memory that was allocated in @a rs during - * #TALER_PQ_extract_result(). - * - * @param rs reult specification to clean up - */ -void -TALER_PQ_cleanup_result (struct TALER_PQ_ResultSpec *rs) -{ - unsigned int i; - - for (i=0; TALER_PQ_RF_END != rs[i].format; i++) - { - switch (rs[i].format) - { - case TALER_PQ_RF_VARSIZE_BLOB: - { - void **dst = rs[i].dst; - if (NULL != *dst) - { - GNUNET_free (*dst); - *dst = NULL; - *rs[i].result_size = 0; - } - break; - } - case TALER_PQ_RF_RSA_PUBLIC_KEY: - { - void **dst = rs[i].dst; - if (NULL != *dst) - { - GNUNET_CRYPTO_rsa_public_key_free (*dst); - *dst = NULL; - } - break; - } - case TALER_PQ_RF_RSA_SIGNATURE: - { - void **dst = rs[i].dst; - if (NULL != *dst) - { - GNUNET_CRYPTO_rsa_signature_free (*dst); - *dst = NULL; - } - } - break; - default: - break; - } - } -} - - -/** - * Extract results from a query result according to the given specification. - * If colums are NULL, the destination is not modified, and #GNUNET_NO - * is returned. - * - * @param result result to process - * @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 - * #GNUNET_NO if at least one result was NULL - * #GNUNET_SYSERR if a result was invalid (non-existing field) - */ -int -TALER_PQ_extract_result (PGresult *result, - struct TALER_PQ_ResultSpec *rs, - int row) -{ - unsigned int i; - int had_null = GNUNET_NO; - - for (i=0; TALER_PQ_RF_END != rs[i].format; i++) - { - struct TALER_PQ_ResultSpec *spec; - - spec = &rs[i]; - switch (spec->format) - { - case TALER_PQ_RF_FIXED_BLOB: - case TALER_PQ_RF_VARSIZE_BLOB: - { - size_t len; - const char *res; - void *dst; - int fnum; - - fnum = PQfnumber (result, - spec->fname); - if (fnum < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' does not exist in result\n", - spec->fname); - return GNUNET_SYSERR; - } - if (PQgetisnull (result, - row, - fnum)) - { - had_null = GNUNET_YES; - continue; - } - - /* if a field is null, continue but - * remember that we now return a different result */ - len = PQgetlength (result, - row, - fnum); - if ( (0 != spec->dst_size) && - (spec->dst_size != len) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' has wrong size (got %u, expected %u)\n", - spec->fname, - (unsigned int) len, - (unsigned int) spec->dst_size); - TALER_PQ_cleanup_result (rs); - return GNUNET_SYSERR; - } - res = PQgetvalue (result, - row, - fnum); - GNUNET_assert (NULL != res); - if (0 == spec->dst_size) - { - if (NULL != spec->result_size) - *spec->result_size = len; - spec->dst_size = len; - dst = GNUNET_malloc (len); - *((void **) spec->dst) = dst; - } - else - dst = spec->dst; - memcpy (dst, - res, - len); - break; - } - case TALER_PQ_RF_AMOUNT_NBO: - { - char *val_name; - char *frac_name; - char *curr_name; - const char *name = spec->fname; - int ret; - - GNUNET_assert (NULL != spec->dst); - GNUNET_assert (sizeof (struct TALER_AmountNBO) == - spec->dst_size); - GNUNET_asprintf (&val_name, - "%s_val", - name); - GNUNET_asprintf (&frac_name, - "%s_frac", - name); - GNUNET_asprintf (&curr_name, - "%s_curr", - name); - ret = TALER_PQ_extract_amount_nbo (result, - row, - val_name, - frac_name, - curr_name, - spec->dst); - GNUNET_free (val_name); - GNUNET_free (frac_name); - GNUNET_free (curr_name); - if (GNUNET_SYSERR == ret) - return GNUNET_SYSERR; - if (GNUNET_OK != ret) - had_null = GNUNET_YES; - break; - } - case TALER_PQ_RF_AMOUNT: - { - char *val_name; - char *frac_name; - char *curr_name; - const char *name = spec->fname; - int ret; - - GNUNET_assert (NULL != spec->dst); - GNUNET_assert (sizeof (struct TALER_Amount) == - spec->dst_size); - GNUNET_asprintf (&val_name, - "%s_val", - name); - GNUNET_asprintf (&frac_name, - "%s_frac", - name); - GNUNET_asprintf (&curr_name, - "%s_curr", - name); - ret = TALER_PQ_extract_amount (result, - row, - val_name, - frac_name, - curr_name, - spec->dst); - GNUNET_free (val_name); - GNUNET_free (frac_name); - GNUNET_free (curr_name); - if (GNUNET_SYSERR == ret) - return GNUNET_SYSERR; - if (GNUNET_OK != ret) - had_null = GNUNET_YES; - break; - } - case TALER_PQ_RF_RSA_PUBLIC_KEY: - { - struct GNUNET_CRYPTO_rsa_PublicKey **pk = spec->dst; - size_t len; - const char *res; - int fnum; - - *pk = NULL; - fnum = PQfnumber (result, - spec->fname); - if (fnum < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' does not exist in result\n", - spec->fname); - return GNUNET_SYSERR; - } - if (PQgetisnull (result, - row, - fnum)) - { - had_null = GNUNET_YES; - continue; - } - - /* if a field is null, continue but - * remember that we now return a different result */ - len = PQgetlength (result, - row, - fnum); - res = PQgetvalue (result, - row, - fnum); - *pk = GNUNET_CRYPTO_rsa_public_key_decode (res, - len); - if (NULL == *pk) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' contains bogus value (fails to decode)\n", - spec->fname); - return GNUNET_SYSERR; - } - break; - } - case TALER_PQ_RF_RSA_SIGNATURE: - { - struct GNUNET_CRYPTO_rsa_Signature **sig = spec->dst; - size_t len; - const char *res; - int fnum; - - *sig = NULL; - fnum = PQfnumber (result, - spec->fname); - if (fnum < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' does not exist in result\n", - spec->fname); - return GNUNET_SYSERR; - } - if (PQgetisnull (result, - row, - fnum)) - { - had_null = GNUNET_YES; - continue; - } - - /* if a field is null, continue but - * remember that we now return a different result */ - len = PQgetlength (result, - row, - fnum); - res = PQgetvalue (result, - row, - fnum); - *sig = GNUNET_CRYPTO_rsa_signature_decode (res, - len); - if (NULL == *sig) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' contains bogus value (fails to decode)\n", - spec->fname); - return GNUNET_SYSERR; - } - break; - } - case TALER_PQ_RF_TIME_ABSOLUTE: - { - struct GNUNET_TIME_Absolute *dst = spec->dst; - const struct GNUNET_TIME_AbsoluteNBO *res; - int fnum; - - fnum = PQfnumber (result, - spec->fname); - if (fnum < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' does not exist in result\n", - spec->fname); - return GNUNET_SYSERR; - } - if (PQgetisnull (result, - row, - fnum)) - { - had_null = GNUNET_YES; - continue; - } - GNUNET_assert (NULL != dst); - GNUNET_assert (sizeof (struct GNUNET_TIME_AbsoluteNBO) == - spec->dst_size); - res = (const struct GNUNET_TIME_AbsoluteNBO *) - PQgetvalue (result, - row, - fnum); - *dst = GNUNET_TIME_absolute_ntoh (*res); - break; - } - case TALER_PQ_RF_UINT16: - { - uint16_t *dst = spec->dst; - const uint16_t *res; - int fnum; - - fnum = PQfnumber (result, - spec->fname); - if (fnum < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' does not exist in result\n", - spec->fname); - return GNUNET_SYSERR; - } - if (PQgetisnull (result, - row, - fnum)) - { - had_null = GNUNET_YES; - continue; - } - GNUNET_assert (NULL != dst); - GNUNET_assert (sizeof (uint16_t) == - spec->dst_size); - res = (uint16_t *) PQgetvalue (result, - row, - fnum); - *dst = ntohs (*res); - break; - } - case TALER_PQ_RF_UINT32: - { - uint32_t *dst = spec->dst; - const uint32_t *res; - int fnum; - - fnum = PQfnumber (result, - spec->fname); - if (fnum < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' does not exist in result\n", - spec->fname); - return GNUNET_SYSERR; - } - if (PQgetisnull (result, - row, - fnum)) - { - had_null = GNUNET_YES; - continue; - } - GNUNET_assert (NULL != dst); - GNUNET_assert (sizeof (uint32_t) == - spec->dst_size); - res = (uint32_t *) PQgetvalue (result, - row, - fnum); - *dst = ntohl (*res); - break; - } - case TALER_PQ_RF_UINT64: - { - uint64_t *dst = spec->dst; - const uint64_t *res; - int fnum; - - fnum = PQfnumber (result, - spec->fname); - if (fnum < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' does not exist in result\n", - spec->fname); - return GNUNET_SYSERR; - } - if (PQgetisnull (result, - row, - fnum)) - { - had_null = GNUNET_YES; - continue; - } - GNUNET_assert (NULL != dst); - GNUNET_assert (sizeof (uint64_t) == - spec->dst_size); - res = (uint64_t *) PQgetvalue (result, - row, - fnum); - *dst = GNUNET_ntohll (*res); - break; - } - case TALER_PQ_RF_JSON: - { - json_t **dst = spec->dst; - char *res; - int fnum; - json_error_t json_error; - size_t slen; - - fnum = PQfnumber (result, - spec->fname); - if (fnum < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' does not exist in result\n", - spec->fname); - return GNUNET_SYSERR; - } - if (PQgetisnull (result, - row, - fnum)) - { - had_null = GNUNET_YES; - continue; - } - GNUNET_assert (NULL != dst); - GNUNET_break (0 == spec->dst_size); - slen = PQgetlength (result, - row, - fnum); - res = (char *) PQgetvalue (result, - row, - fnum); - *dst = json_loadb (res, - slen, - JSON_REJECT_DUPLICATES, - &json_error); - if (NULL == *dst) - { - TALER_json_warn (json_error); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse JSON result for field `%s'\n", - spec->fname); - return GNUNET_SYSERR; - } - break; - } - default: - GNUNET_assert (0); - break; - } - } - if (GNUNET_YES == had_null) - return GNUNET_NO; - return GNUNET_YES; -} - - -/** - * Extract a currency amount from a query result according to the - * given specification. - * - * @param result the result to extract the amount from - * @param row which row of the result to extract the amount from (needed as results can have multiple rows) - * @param val_name name of the column with the amount's "value", must include the substring "_val". - * @param frac_name name of the column with the amount's "fractional" value, must include the substring "_frac". - * @param curr_name name of the column with the amount's currency name, must include the substring "_curr". - * @param[out] r_amount_nbo where to store the amount, in network byte order - * @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) - */ -int -TALER_PQ_extract_amount_nbo (PGresult *result, - int row, - const char *val_name, - const char *frac_name, - const char *curr_name, - struct TALER_AmountNBO *r_amount_nbo) -{ - int val_num; - int frac_num; - int curr_num; - int len; - - /* These checks are simply to check that clients obey by our naming - conventions, and not for any functional reason */ - GNUNET_assert (NULL != - strstr (val_name, - "_val")); - GNUNET_assert (NULL != - strstr (frac_name, - "_frac")); - GNUNET_assert (NULL != - strstr (curr_name, - "_curr")); - /* Set return value to invalid in case we don't finish */ - memset (r_amount_nbo, - 0, - sizeof (struct TALER_AmountNBO)); - val_num = PQfnumber (result, - val_name); - frac_num = PQfnumber (result, - frac_name); - curr_num = PQfnumber (result, - curr_name); - if ( (val_num < 0) || - (frac_num < 0) || - (curr_num < 0) ) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if ( (PQgetisnull (result, - row, - val_num)) || - (PQgetisnull (result, - row, - frac_num)) || - (PQgetisnull (result, - row, - curr_num)) ) - { - GNUNET_break (0); - return GNUNET_NO; - } - /* Note that Postgres stores value in NBO internally, - so no conversion needed in this case */ - r_amount_nbo->value = *(uint64_t *) PQgetvalue (result, - row, - val_num); - r_amount_nbo->fraction = *(uint32_t *) PQgetvalue (result, - row, - frac_num); - len = GNUNET_MIN (TALER_CURRENCY_LEN - 1, - PQgetlength (result, - row, - curr_num)); - memcpy (r_amount_nbo->currency, - PQgetvalue (result, - row, - curr_num), - len); - return GNUNET_OK; -} - - -/** - * Extract a currency amount from a query result according to the - * given specification. - * - * @param result the result to extract the amount from - * @param row which row of the result to extract the amount from (needed as - * results can have multiple rows) - * @param val_name name of the column with the amount's "value", must include - * the substring "_val". - * @param frac_name name of the column with the amount's "fractional" value, - * must include the substring "_frac". - * @param curr_name name of the column with the amount's currency name, must - * include the substring "_curr". - * @param[out] r_amount where to store the amount, in host byte order - * @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) - */ -int -TALER_PQ_extract_amount (PGresult *result, - int row, - const char *val_name, - const char *frac_name, - const char *curr_name, - struct TALER_Amount *r_amount) -{ - struct TALER_AmountNBO amount_nbo; - int ret; - - ret = TALER_PQ_extract_amount_nbo (result, - row, - val_name, - frac_name, - curr_name, - &amount_nbo); - TALER_amount_ntoh (r_amount, - &amount_nbo); - return ret; -} - - -/* end of pq/db_pq.c */ diff --git a/src/pq/pq_helper.c b/src/pq/pq_helper.c deleted file mode 100644 index d245ffdb8..000000000 --- a/src/pq/pq_helper.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - 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; -} - - -/** - * 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 - */ -struct TALER_PQ_QueryParam -TALER_PQ_query_param_absolute_time_nbo(const struct GNUNET_TIME_AbsoluteNBO *x) -{ - struct TALER_PQ_QueryParam res = - TALER_PQ_query_param_auto_from_type (&x->abs_value_us__); - return res; -} - - -/** - * Generate query parameter for an uint16_t in host byte order. - * - * @param x pointer to the query parameter to pass - */ -struct TALER_PQ_QueryParam -TALER_PQ_query_param_uint16 (const uint16_t *x) -{ - struct TALER_PQ_QueryParam res = - { TALER_PQ_QF_UINT16, x, sizeof (*x) }; - return res; -} - - -/** - * Generate query parameter for an uint32_t in host byte order. - * - * @param x pointer to the query parameter to pass - */ -struct TALER_PQ_QueryParam -TALER_PQ_query_param_uint32 (const uint32_t *x) -{ - struct TALER_PQ_QueryParam res = - { TALER_PQ_QF_UINT32, x, sizeof (*x) }; - return res; -} - - -/** - * Generate query parameter for an uint16_t in host byte order. - * - * @param x pointer to the query parameter to pass - */ -struct TALER_PQ_QueryParam -TALER_PQ_query_param_uint64 (const uint64_t *x) -{ - struct TALER_PQ_QueryParam res = - { TALER_PQ_QF_UINT64, x, sizeof (*x) }; - return res; -} - - -/** - * Generate query parameter for a JSON object (stored as a string - * in the DB). - * - * @param x pointer to the json object to pass - */ -struct TALER_PQ_QueryParam -TALER_PQ_query_param_json (const json_t *x) -{ - struct TALER_PQ_QueryParam res = - { TALER_PQ_QF_JSON, x, 0 }; - 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; -} - - -/** - * 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_nbo (const char *name, - struct GNUNET_TIME_AbsoluteNBO *at) -{ - struct TALER_PQ_ResultSpec res = - TALER_PQ_result_spec_auto_from_type(name, &at->abs_value_us__); - return res; -} - - -/** - * uint16_t expected. - * - * @param name name of the field in the table - * @param[out] u16 where to store the result - * @return array entry for the result specification to use - */ -struct TALER_PQ_ResultSpec -TALER_PQ_result_spec_uint16 (const char *name, - uint16_t *u16) -{ - struct TALER_PQ_ResultSpec res = - {TALER_PQ_RF_UINT16, (void *) u16, sizeof (*u16), (name), NULL }; - return res; -} - - -/** - * uint32_t expected. - * - * @param name name of the field in the table - * @param[out] u32 where to store the result - * @return array entry for the result specification to use - */ -struct TALER_PQ_ResultSpec -TALER_PQ_result_spec_uint32 (const char *name, - uint32_t *u32) -{ - struct TALER_PQ_ResultSpec res = - {TALER_PQ_RF_UINT32, (void *) u32, sizeof (*u32), (name), NULL }; - return res; -} - - -/** - * uint64_t expected. - * - * @param name name of the field in the table - * @param[out] u64 where to store the result - * @return array entry for the result specification to use - */ -struct TALER_PQ_ResultSpec -TALER_PQ_result_spec_uint64 (const char *name, - uint64_t *u64) -{ - struct TALER_PQ_ResultSpec res = - {TALER_PQ_RF_UINT64, (void *) u64, sizeof (*u64), (name), NULL }; - return res; -} - - -/** - * json_t expected. - * - * @param name name of the field in the table - * @param[out] jp where to store the result - * @return array entry for the result specification to use - */ -struct TALER_PQ_ResultSpec -TALER_PQ_result_spec_json (const char *name, - json_t **jp) -{ - struct TALER_PQ_ResultSpec res = - {TALER_PQ_RF_JSON, (void *) jp, 0, (name), NULL }; - return res; -} - -/* end of pq_helper.c */ diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c new file mode 100644 index 000000000..5d2e9ce06 --- /dev/null +++ b/src/pq/pq_query_helper.c @@ -0,0 +1,208 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + 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_query_helper.c + * @brief helper functions for Taler-specific libpq (PostGres) interactions + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + * @author Florian Dold + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_pq_lib.h> +#include "taler_pq_lib.h" + + +/** + * Function called to convert input argument into SQL parameters. + * + * @param cls closure + * @param data pointer to input argument, here a `struct TALER_AmountNBO` + * @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_nbo (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 TALER_AmountNBO *amount = data; + unsigned int off = 0; + + GNUNET_assert (3 == param_length); + param_values[off] = (void *) &amount->value; + param_lengths[off] = sizeof (amount->value); + param_formats[off] = 1; + off++; + param_values[off] = (void *) &amount->fraction; + param_lengths[off] = sizeof (amount->fraction); + param_formats[off] = 1; + off++; + param_values[off] = (void *) amount->currency; + param_lengths[off] = strlen (amount->currency); + param_formats[off] = 1; + return 0; +} + + +/** + * 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 GNUNET_PQ_QueryParam +TALER_PQ_query_param_amount_nbo (const struct TALER_AmountNBO *x) +{ + struct GNUNET_PQ_QueryParam res = + { &qconv_amount_nbo, NULL, x, sizeof (*x), 3 }; + return res; +} + + +/** + * Function called to convert input argument into SQL parameters. + * + * @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 (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 TALER_Amount *amount_hbo = data; + struct TALER_AmountNBO *amount; + + amount = GNUNET_new (struct TALER_AmountNBO); + scratch[0] = amount; + TALER_amount_hton (amount, + amount_hbo); + qconv_amount_nbo (cls, + amount, + sizeof (struct TALER_AmountNBO), + param_values, + param_lengths, + param_formats, + param_length, + &scratch[1], + scratch_length - 1); + return 1; +} + + +/** + * 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 GNUNET_PQ_QueryParam +TALER_PQ_query_param_amount (const struct TALER_Amount *x) +{ + struct GNUNET_PQ_QueryParam res = + { &qconv_amount, NULL, x, sizeof (*x), 3 }; + return res; +} + + +/** + * Function called to convert input argument into SQL parameters. + * + * @param cls closure + * @param data pointer to input argument, here a `json_t *` + * @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_json (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 json_t *json = data; + char *str; + + str = json_dumps (json, JSON_COMPACT); + if (NULL == str) + return -1; + scratch[0] = str; + param_values[0] = (void *) str; + param_lengths[0] = strlen (str); + param_formats[0] = 1; + return 1; +} + + +/** + * Generate query parameter for a JSON object (stored as a string + * in the DB). + * + * @param x pointer to the json object to pass + */ +struct GNUNET_PQ_QueryParam +TALER_PQ_query_param_json (const json_t *x) +{ + struct GNUNET_PQ_QueryParam res = + { &qconv_json, NULL, x, 0, 1 }; + return res; +} + + +/* end of pq/pq_query_helper.c */ diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c new file mode 100644 index 000000000..c8b3b01fc --- /dev/null +++ b/src/pq/pq_result_helper.c @@ -0,0 +1,358 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + 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_result_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" + + +/** + * Extract a currency amount from a query result according to the + * given specification. + * + * @param result the result to extract the amount from + * @param row which row of the result to extract the amount from (needed as results can have multiple rows) + * @param val_name name of the column with the amount's "value", must include the substring "_val". + * @param frac_name name of the column with the amount's "fractional" value, must include the substring "_frac". + * @param curr_name name of the column with the amount's currency name, must include the substring "_curr". + * @param[out] r_amount_nbo where to store the amount, in network byte order + * @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 int +extract_amount_nbo_helper (PGresult *result, + int row, + const char *val_name, + const char *frac_name, + const char *curr_name, + struct TALER_AmountNBO *r_amount_nbo) +{ + int val_num; + int frac_num; + int curr_num; + int len; + + /* These checks are simply to check that clients obey by our naming + conventions, and not for any functional reason */ + GNUNET_assert (NULL != + strstr (val_name, + "_val")); + GNUNET_assert (NULL != + strstr (frac_name, + "_frac")); + GNUNET_assert (NULL != + strstr (curr_name, + "_curr")); + /* Set return value to invalid in case we don't finish */ + memset (r_amount_nbo, + 0, + sizeof (struct TALER_AmountNBO)); + val_num = PQfnumber (result, + val_name); + frac_num = PQfnumber (result, + frac_name); + curr_num = PQfnumber (result, + curr_name); + if ( (val_num < 0) || + (frac_num < 0) || + (curr_num < 0) ) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if ( (PQgetisnull (result, + row, + val_num)) || + (PQgetisnull (result, + row, + frac_num)) || + (PQgetisnull (result, + row, + curr_num)) ) + { + GNUNET_break (0); + return GNUNET_NO; + } + /* Note that Postgres stores value in NBO internally, + so no conversion needed in this case */ + r_amount_nbo->value = *(uint64_t *) PQgetvalue (result, + row, + val_num); + r_amount_nbo->fraction = *(uint32_t *) PQgetvalue (result, + row, + frac_num); + len = GNUNET_MIN (TALER_CURRENCY_LEN - 1, + PQgetlength (result, + row, + curr_num)); + memcpy (r_amount_nbo->currency, + PQgetvalue (result, + row, + curr_num), + len); + return GNUNET_OK; +} + + +/** + * Extract data from a Postgres database @a result at row @a row. + * + * @param cls closure + * @param result where to extract data from + * @param int 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 int +extract_amount_nbo (void *cls, + PGresult *result, + int row, + const char *fname, + size_t *dst_size, + void *dst) +{ + char *val_name; + char *frac_name; + char *curr_name; + int ret; + + GNUNET_asprintf (&val_name, + "%s_val", + fname); + GNUNET_asprintf (&frac_name, + "%s_frac", + fname); + GNUNET_asprintf (&curr_name, + "%s_curr", + fname); + ret = extract_amount_nbo_helper (result, + row, + val_name, + frac_name, + curr_name, + dst); + GNUNET_free (val_name); + GNUNET_free (frac_name); + GNUNET_free (curr_name); + return ret; +} + + +/** + * 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 GNUNET_PQ_ResultSpec +TALER_PQ_result_spec_amount_nbo (const char *name, + struct TALER_AmountNBO *amount) +{ + struct GNUNET_PQ_ResultSpec res = + { &extract_amount_nbo, NULL, NULL, + (void *) amount, sizeof (*amount), + name, NULL }; + return res; +} + + +/** + * Extract data from a Postgres database @a result at row @a row. + * + * @param cls closure + * @param result where to extract data from + * @param int 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 int +extract_amount (void *cls, + PGresult *result, + int row, + const char *fname, + size_t *dst_size, + void *dst) +{ + struct TALER_Amount *r_amount = dst; + char *val_name; + char *frac_name; + char *curr_name; + struct TALER_AmountNBO amount_nbo; + int ret; + + GNUNET_asprintf (&val_name, + "%s_val", + fname); + GNUNET_asprintf (&frac_name, + "%s_frac", + fname); + GNUNET_asprintf (&curr_name, + "%s_curr", + fname); + ret = extract_amount_nbo_helper (result, + row, + val_name, + frac_name, + curr_name, + &amount_nbo); + TALER_amount_ntoh (r_amount, + &amount_nbo); + GNUNET_free (val_name); + GNUNET_free (frac_name); + GNUNET_free (curr_name); + return ret; +} + + +/** + * 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 GNUNET_PQ_ResultSpec +TALER_PQ_result_spec_amount (const char *name, + struct TALER_Amount *amount) +{ + struct GNUNET_PQ_ResultSpec res = + { &extract_amount, NULL, NULL, + (void *) amount, sizeof (*amount), + name, NULL }; + return res; +} + + +/** + * Extract data from a Postgres database @a result at row @a row. + * + * @param cls closure + * @param result where to extract data from + * @param int 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 int +extract_json (void *cls, + PGresult *result, + int row, + const char *fname, + size_t *dst_size, + void *dst) +{ + json_t **j_dst = dst; + const char *res; + int fnum; + json_error_t json_error; + size_t slen; + + fnum = PQfnumber (result, + fname); + if (fnum < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Field `%s' does not exist in result\n", + fname); + return GNUNET_SYSERR; + } + if (PQgetisnull (result, + row, + fnum)) + return GNUNET_NO; + slen = PQgetlength (result, + row, + fnum); + res = (const char *) PQgetvalue (result, + row, + fnum); + *j_dst = json_loadb (res, + slen, + JSON_REJECT_DUPLICATES, + &json_error); + if (NULL == *j_dst) + { + TALER_json_warn (json_error); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse JSON result for field `%s'\n", + fname); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Function called to clean up memory allocated + * by a #GNUNET_PQ_ResultConverter. + * + * @param cls closure + * @param rd result data to clean up + */ +static void +clean_json (void *cls, + void *rd) +{ + json_t **dst = rd; + + if (NULL != *dst) + { + json_decref (*dst); + *dst = NULL; + } +} + + +/** + * json_t expected. + * + * @param name name of the field in the table + * @param[out] jp where to store the result + * @return array entry for the result specification to use + */ +struct GNUNET_PQ_ResultSpec +TALER_PQ_result_spec_json (const char *name, + json_t **jp) +{ + struct GNUNET_PQ_ResultSpec res = + { &extract_json, &clean_json, NULL, + (void *) jp, 0, + name, NULL }; + return res; +} + +/* end of pq_result_helper.c */ diff --git a/src/pq/test_pq.c b/src/pq/test_pq.c index f0413d1ff..95cfb715d 100644 --- a/src/pq/test_pq.c +++ b/src/pq/test_pq.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2015 GNUnet e.V. + (C) 2015, 2016 GNUnet e.V. 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 @@ -48,47 +48,27 @@ postgres_prepare (PGconn *db_conn) PREPARE ("test_insert", "INSERT INTO test_pq (" - " pub" - ",sig" - ",abs_time" - ",forever" - ",hash" - ",hamount_val" + " hamount_val" ",hamount_frac" ",hamount_curr" ",namount_val" ",namount_frac" ",namount_curr" - ",vsize" - ",u16" - ",u32" - ",u64" ",json" ") VALUES " "($1, $2, $3, $4, $5, $6," - "$7, $8, $9, $10, $11, $12, $13, $14, $15, $16);", - 16, NULL); + "$7);", + 7, NULL); PREPARE ("test_select", "SELECT" - " pub" - ",sig" - ",abs_time" - ",forever" - ",hash" - ",hamount_val" + " hamount_val" ",hamount_frac" ",hamount_curr" ",namount_val" ",namount_frac" ",namount_curr" - ",vsize" - ",u16" - ",u32" - ",u64" ",json" - " FROM test_pq" - " ORDER BY abs_time DESC " - " LIMIT 1;", + " FROM test_pq;", 0, NULL); return GNUNET_OK; #undef PREPARE @@ -103,40 +83,15 @@ postgres_prepare (PGconn *db_conn) static int run_queries (PGconn *conn) { - struct GNUNET_CRYPTO_rsa_PublicKey *pub; - struct GNUNET_CRYPTO_rsa_PublicKey *pub2 = NULL; - struct GNUNET_CRYPTO_rsa_Signature *sig; - struct GNUNET_CRYPTO_rsa_Signature *sig2 = NULL; - struct GNUNET_TIME_Absolute abs_time = GNUNET_TIME_absolute_get (); - struct GNUNET_TIME_Absolute abs_time2; - struct GNUNET_TIME_Absolute forever = GNUNET_TIME_UNIT_FOREVER_ABS; - struct GNUNET_TIME_Absolute forever2; - struct GNUNET_HashCode hc; - struct GNUNET_HashCode hc2; struct TALER_Amount hamount; struct TALER_Amount hamount2; struct TALER_AmountNBO namount; struct TALER_AmountNBO namount2; PGresult *result; int ret; - struct GNUNET_CRYPTO_rsa_PrivateKey *priv; - char msg[] = "Hello"; - void *msg2; - size_t msg2_len; - uint16_t u16; - uint16_t u162; - uint32_t u32; - uint32_t u322; - uint64_t u64; - uint64_t u642; json_t *json; json_t *json2; - 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)); GNUNET_assert (GNUNET_OK == TALER_string_to_amount ("EUR:5.5", &hamount)); @@ -145,87 +100,53 @@ run_queries (PGconn *conn) GNUNET_assert (GNUNET_OK == TALER_string_to_amount ("EUR:4.4", &hamount)); - u16 = 16; - u32 = 32; - u64 = 64; json = json_object (); json_object_set (json, "foo", json_integer (42)); GNUNET_assert (NULL != json); - /* FIXME: test TALER_PQ_result_spec_variable_size */ + /* FIXME: test GNUNET_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), + struct GNUNET_PQ_QueryParam params_insert[] = { 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_uint16 (&u16), - TALER_PQ_query_param_uint32 (&u32), - TALER_PQ_query_param_uint64 (&u64), TALER_PQ_query_param_json (json), - TALER_PQ_query_param_end + GNUNET_PQ_query_param_end }; - struct TALER_PQ_QueryParam params_select[] = { - TALER_PQ_query_param_end + struct GNUNET_PQ_QueryParam params_select[] = { + GNUNET_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), + struct GNUNET_PQ_ResultSpec results_select[] = { 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_uint16 ("u16", &u162), - TALER_PQ_result_spec_uint32 ("u32", &u322), - TALER_PQ_result_spec_uint64 ("u64", &u642), TALER_PQ_result_spec_json ("json", &json2), - TALER_PQ_result_spec_end + GNUNET_PQ_result_spec_end }; - result = TALER_PQ_exec_prepared (conn, - "test_insert", - params_insert); + result = GNUNET_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); + result = GNUNET_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))); + ret = GNUNET_PQ_extract_result (result, + results_select, + 0); GNUNET_break (0 == TALER_amount_cmp (&hamount, &hamount2)); @@ -237,28 +158,11 @@ run_queries (PGconn *conn) 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)); - GNUNET_break (16 == u162); - GNUNET_break (32 == u322); - GNUNET_break (64 == u642); GNUNET_break (42 == json_integer_value (json_object_get (json2, "foo"))); json_decref (json2); - TALER_PQ_cleanup_result (results_select); + GNUNET_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; @@ -290,21 +194,12 @@ main(int argc, result = PQexec (conn, "CREATE TEMPORARY TABLE IF NOT EXISTS test_pq (" - " pub BYTEA NOT NULL" - ",sig BYTEA NOT NULL" - ",abs_time INT8 NOT NULL" - ",forever INT8 NOT NULL" - ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)" - ",hamount_val INT8 NOT NULL" + " hamount_val INT8 NOT NULL" ",hamount_frac INT4 NOT NULL" ",hamount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" ",namount_val INT8 NOT NULL" ",namount_frac INT4 NOT NULL" ",namount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",vsize VARCHAR NOT NULL" - ",u16 INT2 NOT NULL" - ",u32 INT4 NOT NULL" - ",u64 INT8 NOT NULL" ",json VARCHAR NOT NULL" ")"); if (PGRES_COMMAND_OK != PQresultStatus (result)) |