aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/taler_pq_lib.h50
-rw-r--r--src/pq/db_pq.c200
2 files changed, 173 insertions, 77 deletions
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<i; j++)
+ {
if (0 == rs[j].dst_size)
{
GNUNET_free (rs[j].dst);
rs[j].dst = NULL;
- *rs[j].result_size = 0;
+ if (NULL != rs[j].result_size)
+ *rs[j].result_size = 0;
}
+ }
return GNUNET_SYSERR;
}
- res = PQgetvalue (result, row, fnum);
+ res = PQgetvalue (result,
+ row,
+ fnum);
GNUNET_assert (NULL != res);
if (0 == rs[i].dst_size)
{
- *rs[i].result_size = len;
- *((void **) rs[i].dst) = GNUNET_malloc (len);
- rs[i].dst = *((void **) rs[i].dst);
+ if (NULL != rs[i].result_size)
+ *rs[i].result_size = len;
+ rs[i].dst_size = len;
+ rs[i].dst = GNUNET_malloc (len);
}
- memcpy (rs[i].dst, res, len);
+ memcpy (rs[i].dst,
+ res,
+ len);
}
if (GNUNET_YES == had_null)
return GNUNET_NO;
@@ -140,21 +157,21 @@ TALER_PQ_extract_result (PGresult *result,
}
-int
-TALER_PQ_field_isnull (PGresult *result,
- int row,
- const char *fname)
-{
- int fnum;
-
- fnum = PQfnumber (result, fname);
- GNUNET_assert (fnum >= 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 */