fix #3729 (documentation, code hygene for pq library)

This commit is contained in:
Christian Grothoff 2015-04-15 22:02:59 +02:00
parent 0a0feeea86
commit 790b331a8d
2 changed files with 173 additions and 77 deletions

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER 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 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 terms of the GNU General Public License as published by the Free Software
@ -32,7 +32,7 @@
struct TALER_PQ_QueryParam struct TALER_PQ_QueryParam
{ {
/** /**
* Data or NULL * Data or NULL.
*/ */
const void *data; const void *data;
@ -43,11 +43,12 @@ struct TALER_PQ_QueryParam
/** /**
* Non-null if this is not the last parameter. * 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; int more;
}; };
/** /**
* End of query parameter specification. * End of query parameter specification.
*/ */
@ -93,7 +94,7 @@ struct TALER_PQ_ResultSpec
char *fname; char *fname;
/** /**
* Actual size of the result. * Where to store actual size of the result.
*/ */
size_t *result_size; 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 } #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` * 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))) #define TALER_PQ_RESULT_SPEC(name, dst) TALER_PQ_RESULT_SPEC_SIZED(name, dst, sizeof (*(dst)))
/** /**
* Variable-size result expected. * 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 * If colums are NULL, the destination is not modified, and GNUNET_NO
* is returned. * 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 * @return
* #GNUNET_YES if all results could be extracted * #GNUNET_YES if all results could be extracted
* #GNUNET_NO if at least one result was NULL * #GNUNET_NO if at least one result was NULL
@ -162,12 +168,21 @@ TALER_PQ_extract_result (PGresult *result,
int row); int row);
int /**
TALER_PQ_field_isnull (PGresult *result, * Extract a currency amount from a query result according to the
int row, * given specification.
const char *fname); *
* @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 int
TALER_PQ_extract_amount_nbo (PGresult *result, TALER_PQ_extract_amount_nbo (PGresult *result,
int row, int row,
@ -177,6 +192,21 @@ TALER_PQ_extract_amount_nbo (PGresult *result,
struct TALER_AmountNBO *r_amount_nbo); 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 int
TALER_PQ_extract_amount (PGresult *result, TALER_PQ_extract_amount (PGresult *result,
int row, int row,

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER 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 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 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 char *name,
const struct TALER_PQ_QueryParam *params) const struct TALER_PQ_QueryParam *params)
{ {
unsigned len; unsigned int len;
unsigned i; unsigned int i;
/* count the number of parameters */ /* count the number of parameters */
{ {
@ -45,7 +45,6 @@ TALER_PQ_exec_prepared (PGconn *db_conn,
} }
/* new scope to allow stack allocation without alloca */ /* new scope to allow stack allocation without alloca */
{ {
void *param_values[len]; void *param_values[len];
int param_lengths[len]; int param_lengths[len];
@ -57,10 +56,13 @@ TALER_PQ_exec_prepared (PGconn *db_conn,
param_lengths[i] = params[i].size; param_lengths[i] = params[i].size;
param_formats[i] = 1; param_formats[i] = 1;
} }
return PQexecPrepared (db_conn, name, len, return PQexecPrepared (db_conn,
name,
len,
(const char **) param_values, (const char **) param_values,
param_lengths, 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 * If colums are NULL, the destination is not modified, and #GNUNET_NO
* is returned. * 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 * @return
* #GNUNET_YES if all results could be extracted * #GNUNET_YES if all results could be extracted
* #GNUNET_NO if at least one result was NULL * #GNUNET_NO if at least one result was NULL
@ -84,55 +89,67 @@ TALER_PQ_extract_result (PGresult *result,
size_t len; size_t len;
unsigned int i; unsigned int i;
unsigned int j; unsigned int j;
const char *res;
int fnum;
for (i=0; NULL != rs[i].fname; i++) 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) if (fnum < 0)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 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); rs[i].fname);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
/* if a field is null, continue but /* if a field is null, continue but
* remember that we now return a different result */ * remember that we now return a different result */
if (PQgetisnull (result, row, fnum)) if (PQgetisnull (result,
row,
fnum))
{ {
had_null = GNUNET_YES; had_null = GNUNET_YES;
continue; continue;
} }
const char *res; len = PQgetlength (result,
len = PQgetlength (result, row, fnum); row,
fnum);
if ( (0 != rs[i].dst_size) && if ( (0 != rs[i].dst_size) &&
(rs[i].dst_size != len) ) (rs[i].dst_size != len) )
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 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, rs[i].fname,
(unsigned int) len, (unsigned int) len,
(unsigned int) rs[i].dst_size); (unsigned int) rs[i].dst_size);
for (j=0; j<i; j++) for (j=0; j<i; j++)
{
if (0 == rs[j].dst_size) if (0 == rs[j].dst_size)
{ {
GNUNET_free (rs[j].dst); GNUNET_free (rs[j].dst);
rs[j].dst = NULL; rs[j].dst = NULL;
*rs[j].result_size = 0; if (NULL != rs[j].result_size)
*rs[j].result_size = 0;
} }
}
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
res = PQgetvalue (result, row, fnum); res = PQgetvalue (result,
row,
fnum);
GNUNET_assert (NULL != res); GNUNET_assert (NULL != res);
if (0 == rs[i].dst_size) if (0 == rs[i].dst_size)
{ {
*rs[i].result_size = len; if (NULL != rs[i].result_size)
*((void **) rs[i].dst) = GNUNET_malloc (len); *rs[i].result_size = len;
rs[i].dst = *((void **) rs[i].dst); 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) if (GNUNET_YES == had_null)
return GNUNET_NO; return GNUNET_NO;
@ -140,21 +157,21 @@ TALER_PQ_extract_result (PGresult *result,
} }
int /**
TALER_PQ_field_isnull (PGresult *result, * Extract a currency amount from a query result according to the
int row, * given specification.
const char *fname) *
{ * @param result the result to extract the amount from
int fnum; * @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".
fnum = PQfnumber (result, fname); * @param frac_name name of the column with the amount's "fractional" value, must include the substring "_frac".
GNUNET_assert (fnum >= 0); * @param curr_name name of the column with the amount's currency name, must include the substring "_curr".
if (PQgetisnull (result, row, fnum)) * @param[out] r_amount_nbo where to store the amount, in network byte order
return GNUNET_YES; * @return
return GNUNET_NO; * #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 int
TALER_PQ_extract_amount_nbo (PGresult *result, TALER_PQ_extract_amount_nbo (PGresult *result,
int row, int row,
@ -168,33 +185,83 @@ TALER_PQ_extract_amount_nbo (PGresult *result,
int curr_num; int curr_num;
int len; int len;
GNUNET_assert (NULL != strstr (val_name, "_val")); /* These checks are simply to check that clients obey by our naming
GNUNET_assert (NULL != strstr (frac_name, "_frac")); conventions, and not for any functional reason */
GNUNET_assert (NULL != strstr (curr_name, "_curr")); GNUNET_assert (NULL !=
strstr (val_name,
val_num = PQfnumber (result, val_name); "_val"));
GNUNET_assert (val_num >= 0); GNUNET_assert (NULL !=
frac_num = PQfnumber (result, frac_name); strstr (frac_name,
GNUNET_assert (frac_num >= 0); "_frac"));
curr_num = PQfnumber (result, curr_name); GNUNET_assert (NULL !=
GNUNET_assert (curr_num >= 0); strstr (curr_name,
"_curr"));
r_amount_nbo->value = *(uint64_t *) PQgetvalue (result, row, val_num); /* Set return value to invalid in case we don't finish */
r_amount_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, frac_num); memset (r_amount_nbo,
memset (r_amount_nbo->currency, 0,
0, sizeof (struct TALER_AmountNBO));
TALER_CURRENCY_LEN); 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, len = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
PQgetlength (result, row, curr_num)); PQgetlength (result,
row,
curr_num));
memcpy (r_amount_nbo->currency, memcpy (r_amount_nbo->currency,
PQgetvalue (result, PQgetvalue (result,
row, row,
curr_num), curr_num),
len); len);
return GNUNET_OK; 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 int
TALER_PQ_extract_amount (PGresult *result, TALER_PQ_extract_amount (PGresult *result,
int row, int row,
@ -204,19 +271,18 @@ TALER_PQ_extract_amount (PGresult *result,
struct TALER_Amount *r_amount) struct TALER_Amount *r_amount)
{ {
struct TALER_AmountNBO amount_nbo; struct TALER_AmountNBO amount_nbo;
int ret;
(void) ret = TALER_PQ_extract_amount_nbo (result,
TALER_PQ_extract_amount_nbo (result, row,
row, val_name,
val_name, frac_name,
frac_name, curr_name,
curr_name, &amount_nbo);
&amount_nbo); TALER_amount_ntoh (r_amount,
r_amount->value = GNUNET_ntohll (amount_nbo.value); &amount_nbo);
r_amount->fraction = ntohl (amount_nbo.fraction); return ret;
(void) strncpy (r_amount->currency, amount_nbo.currency, TALER_CURRENCY_LEN);
return GNUNET_OK;
} }
/* end of pq/db_pq.c */ /* end of pq/db_pq.c */