From 2b5a7c8748405fd8f28c840c3142e5ff35f2fa36 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 6 Feb 2016 17:39:18 +0100 Subject: move to new libgnunetpq library, simplifying libtalerpq --- src/pq/pq_result_helper.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 src/pq/pq_result_helper.c (limited to 'src/pq/pq_result_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 +*/ +/** + * @file pq/pq_result_helper.c + * @brief functions to initialize parameter arrays + * @author Christian Grothoff + */ +#include "platform.h" +#include +#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 */ -- cgit v1.2.3