diff --git a/src/include/taler_pq_lib.h b/src/include/taler_pq_lib.h index 67e9f93ab..0db30f1a0 100644 --- a/src/include/taler_pq_lib.h +++ b/src/include/taler_pq_lib.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014 Christian Grothoff (and other contributing authors) + 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 @@ -32,7 +32,7 @@ struct TALER_PQ_QueryParam { /** - * Data or NULL + * Data or NULL. */ const void *data; @@ -43,11 +43,12 @@ struct TALER_PQ_QueryParam /** * Non-null if this is not the last parameter. - * This allows for null as sentinal value. + * This allows us to detect the end of the list. */ int more; }; + /** * End of query parameter specification. */ @@ -93,7 +94,7 @@ struct TALER_PQ_ResultSpec char *fname; /** - * Actual size of the result. + * Where to store actual size of the result. */ size_t *result_size; @@ -114,6 +115,7 @@ struct TALER_PQ_ResultSpec */ #define TALER_PQ_RESULT_SPEC_SIZED(name, dst, s) { (void *) (dst), (s), (name), NULL } + /** * We expect a fixed-size result, with size determined by the type of `* dst` * @@ -122,6 +124,7 @@ struct TALER_PQ_ResultSpec */ #define TALER_PQ_RESULT_SPEC(name, dst) TALER_PQ_RESULT_SPEC_SIZED(name, dst, sizeof (*(dst))) + /** * Variable-size result expected. * @@ -151,6 +154,9 @@ TALER_PQ_exec_prepared (PGconn *db_conn, * 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 @@ -162,12 +168,21 @@ TALER_PQ_extract_result (PGresult *result, int row); -int -TALER_PQ_field_isnull (PGresult *result, - int row, - const char *fname); - - +/** + * 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, @@ -177,6 +192,21 @@ TALER_PQ_extract_amount_nbo (PGresult *result, struct TALER_AmountNBO *r_amount_nbo); +/** + * 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, diff --git a/src/pq/db_pq.c b/src/pq/db_pq.c index 48ffb6c88..f0412d49f 100644 --- a/src/pq/db_pq.c +++ b/src/pq/db_pq.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014 Christian Grothoff (and other contributing authors) + 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 @@ -33,8 +33,8 @@ TALER_PQ_exec_prepared (PGconn *db_conn, const char *name, const struct TALER_PQ_QueryParam *params) { - unsigned len; - unsigned i; + unsigned int len; + unsigned int i; /* count the number of parameters */ { @@ -45,7 +45,6 @@ TALER_PQ_exec_prepared (PGconn *db_conn, } /* new scope to allow stack allocation without alloca */ - { void *param_values[len]; int param_lengths[len]; @@ -57,10 +56,13 @@ TALER_PQ_exec_prepared (PGconn *db_conn, param_lengths[i] = params[i].size; param_formats[i] = 1; } - return PQexecPrepared (db_conn, name, len, + return PQexecPrepared (db_conn, + name, + len, (const char **) param_values, param_lengths, - param_formats, 1); + param_formats, + 1); } } @@ -70,6 +72,9 @@ TALER_PQ_exec_prepared (PGconn *db_conn, * 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 @@ -84,55 +89,67 @@ TALER_PQ_extract_result (PGresult *result, size_t len; unsigned int i; unsigned int j; + const char *res; + int fnum; for (i=0; NULL != rs[i].fname; i++) { - int fnum; - - fnum = PQfnumber (result, rs[i].fname); + fnum = PQfnumber (result, + rs[i].fname); if (fnum < 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "field '%s' does not exist in result\n", + "Field `%s' does not exist in result\n", rs[i].fname); return GNUNET_SYSERR; } /* if a field is null, continue but * remember that we now return a different result */ - if (PQgetisnull (result, row, fnum)) + if (PQgetisnull (result, + row, + fnum)) { had_null = GNUNET_YES; continue; } - const char *res; - len = PQgetlength (result, row, fnum); + len = PQgetlength (result, + row, + fnum); if ( (0 != rs[i].dst_size) && (rs[i].dst_size != len) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "field '%s' has wrong size (got %u, expected %u)\n", + "Field `%s' has wrong size (got %u, expected %u)\n", rs[i].fname, (unsigned int) len, (unsigned int) rs[i].dst_size); for (j=0; j= 0); - if (PQgetisnull (result, row, fnum)) - return GNUNET_YES; - return GNUNET_NO; -} - - +/** + * 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, @@ -168,33 +185,83 @@ TALER_PQ_extract_amount_nbo (PGresult *result, int curr_num; int len; - GNUNET_assert (NULL != strstr (val_name, "_val")); - GNUNET_assert (NULL != strstr (frac_name, "_frac")); - GNUNET_assert (NULL != strstr (curr_name, "_curr")); - - val_num = PQfnumber (result, val_name); - GNUNET_assert (val_num >= 0); - frac_num = PQfnumber (result, frac_name); - GNUNET_assert (frac_num >= 0); - curr_num = PQfnumber (result, curr_name); - GNUNET_assert (curr_num >= 0); - - r_amount_nbo->value = *(uint64_t *) PQgetvalue (result, row, val_num); - r_amount_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, frac_num); - memset (r_amount_nbo->currency, - 0, - TALER_CURRENCY_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)); + PQgetlength (result, + row, + curr_num)); memcpy (r_amount_nbo->currency, - PQgetvalue (result, - row, - curr_num), + 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, @@ -204,19 +271,18 @@ TALER_PQ_extract_amount (PGresult *result, struct TALER_Amount *r_amount) { struct TALER_AmountNBO amount_nbo; + int ret; - (void) - TALER_PQ_extract_amount_nbo (result, - row, - val_name, - frac_name, - curr_name, - &amount_nbo); - r_amount->value = GNUNET_ntohll (amount_nbo.value); - r_amount->fraction = ntohl (amount_nbo.fraction); - (void) strncpy (r_amount->currency, amount_nbo.currency, TALER_CURRENCY_LEN); - - return GNUNET_OK; + 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 */