summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-05-06 11:13:09 +0200
committerChristian Grothoff <christian@grothoff.org>2015-05-06 11:13:09 +0200
commit85e59ceb1a704db77b8d48b5e9ccc26c0283559b (patch)
treecd4e9908c7d174a1060d1b470014e318a1896f82
parent4af6cbb3757a3be555b8dfec58cf1bd50afcd609 (diff)
downloadexchange-85e59ceb1a704db77b8d48b5e9ccc26c0283559b.tar.gz
exchange-85e59ceb1a704db77b8d48b5e9ccc26c0283559b.tar.bz2
exchange-85e59ceb1a704db77b8d48b5e9ccc26c0283559b.zip
expanding PQ APIs to be able to handle Amounts nicely (and be extensible for additional data types in the future)
-rw-r--r--src/include/taler_pq_lib.h65
-rw-r--r--src/pq/db_pq.c235
2 files changed, 220 insertions, 80 deletions
diff --git a/src/include/taler_pq_lib.h b/src/include/taler_pq_lib.h
index 6d4ac8cb8..f6f64178a 100644
--- a/src/include/taler_pq_lib.h
+++ b/src/include/taler_pq_lib.h
@@ -27,10 +27,46 @@
#include "taler_util.h"
/**
+ * Different formats of results that can be added to a query.
+ */
+enum TALER_PQ_QueryFormat
+{
+
+ /**
+ * List terminator.
+ */
+ TALER_PQ_QF_END,
+
+ /**
+ * We have a fixed-size result (binary blob, no endianess conversion).
+ */
+ TALER_PQ_QF_FIXED_BLOB,
+
+ /**
+ * We have a variable-size result (binary blob, no endianess conversion).
+ */
+ TALER_PQ_QF_VARSIZE_BLOB,
+
+ /**
+ * We have a currency amount (with endianess conversion).
+ * Data points to a `struct TALER_AmountNBO`, size is not used.
+ */
+ TALER_PQ_QF_AMOUNT_NBO
+};
+
+
+/**
* @brief Description of a DB query parameter.
*/
struct TALER_PQ_QueryParam
{
+
+ /**
+ * Format of the rest of the entry, determines the data
+ * type that is being added to the query.
+ */
+ enum TALER_PQ_QueryFormat format;
+
/**
* Data or NULL.
*/
@@ -41,18 +77,13 @@ struct TALER_PQ_QueryParam
*/
size_t size;
- /**
- * Non-null if this is not the last parameter.
- * This allows us to detect the end of the list.
- */
- int more;
};
/**
* End of query parameter specification.
*/
-#define TALER_PQ_QUERY_PARAM_END { NULL, 0, 0 }
+#define TALER_PQ_QUERY_PARAM_END { TALER_PQ_QF_END, NULL, 0 }
/**
* Generate fixed-size query parameter with size given explicitly.
@@ -60,7 +91,7 @@ struct TALER_PQ_QueryParam
* @param x pointer to the query parameter to pass
* @param s number of bytes of @a x to use for the query
*/
-#define TALER_PQ_QUERY_PARAM_PTR_SIZED(x, s) { (x), (s), 1 }
+#define TALER_PQ_QUERY_PARAM_PTR_SIZED(x, s) { TALER_PQ_QF_FIXED_BLOB, (x), (s) }
/**
* Generate fixed-size query parameter with size determined
@@ -68,7 +99,15 @@ struct TALER_PQ_QueryParam
*
* @param x pointer to the query parameter to pass.
*/
-#define TALER_PQ_QUERY_PARAM_PTR(x) TALER_PQ_QUERY_PARAM_PTR_SIZED(x, sizeof (*(x)))
+#define TALER_PQ_QUERY_PARAM_PTR(x) { TALER_PQ_QF_VARSIZE_BLOB, x, sizeof (*(x)) }
+
+/**
+ * Generate fixed-size query parameter with size determined
+ * by variable type.
+ *
+ * @param x pointer to the query parameter to pass.
+ */
+#define TALER_PQ_QUERY_PARAM_AMOUNT_NBO(x) { TALER_PQ_QF_AMOUNT_NBO, x, sizeof (*(x)) }
/**
@@ -93,10 +132,10 @@ enum TALER_PQ_ResultFormat
TALER_PQ_RF_VARSIZE_BLOB,
/**
- * We have a currency amount (with endianess conversion).
- * Data points to a `struct TALER_Amount`, size is not used.
+ * We have a currency amount.
+ * Data points to a `struct TALER_AmountNBO`, size is not used.
*/
- TALER_PQ_RF_AMOUNT
+ TALER_PQ_RF_AMOUNT_NBO
};
@@ -176,7 +215,7 @@ struct TALER_PQ_ResultSpec
* @param name name of the field in the table
* @param amount a `struct TALER_Amount` where to store the result
*/
-#define TALER_PQ_RESULT_SPEC_AMOUNT(name, amount) {TALER_PQ_RF_AMOUNT, (void *) (&dst), 0, (name), sptr }
+#define TALER_PQ_RESULT_SPEC_AMOUNT(name, amount) {TALER_PQ_RF_AMOUNT, (void *) (&dst), sizeof (amount), (name), NULL }
/**
@@ -264,4 +303,4 @@ TALER_PQ_extract_amount (PGresult *result,
#endif /* TALER_PQ_LIB_H_ */
-/* end of db/taler_pq_lib.h */
+/* end of include/taler_pq_lib.h */
diff --git a/src/pq/db_pq.c b/src/pq/db_pq.c
index 1ec6e8a73..2c0fccfa9 100644
--- a/src/pq/db_pq.c
+++ b/src/pq/db_pq.c
@@ -27,6 +27,11 @@
/**
* 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,
@@ -37,11 +42,26 @@ TALER_PQ_exec_prepared (PGconn *db_conn,
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;
- for (len = 0, x = params;
- x->more;
- len++, x++);
+ const struct TALER_PQ_QueryParam *x = &params[i];
+
+ switch (x->format)
+ {
+ case TALER_PQ_RF_FIXED_BLOB:
+ case TALER_PQ_RF_VARSIZE_BLOB:
+ len++;
+ break;
+ case TALER_PQ_RF_AMOUNT_NBO:
+ len += 3;
+ break;
+ default:
+ /* format not supported */
+ GNUNET_assert (0);
+ break;
+ }
}
/* new scope to allow stack allocation without alloca */
@@ -49,13 +69,48 @@ TALER_PQ_exec_prepared (PGconn *db_conn,
void *param_values[len];
int param_lengths[len];
int param_formats[len];
+ unsigned int off;
- for (i = 0; i < len; i += 1)
+ i = 0;
+ off = 0;
+ while (TALER_PQ_QF_END != params[i].format)
{
- param_values[i] = (void *) params[i].data;
- param_lengths[i] = params[i].size;
- param_formats[i] = 1;
+ const struct TALER_PQ_QueryParam *x = &params[i];
+
+ switch (x->format)
+ {
+ case TALER_PQ_RF_FIXED_BLOB:
+ case TALER_PQ_RF_VARSIZE_BLOB:
+ param_values[off] = (void *) x->data;
+ param_lengths[off] = x->size;
+ param_formats[off] = 1;
+ off++;
+ break;
+ case TALER_PQ_RF_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) + 1;
+ param_formats[off] = 1;
+ off++;
+ }
+ break;
+ default:
+ /* format not supported */
+ GNUNET_assert (0);
+ break;
+ }
}
+ GNUNET_assert (off == len);
return PQexecPrepared (db_conn,
name,
len,
@@ -85,75 +140,121 @@ TALER_PQ_extract_result (PGresult *result,
struct TALER_PQ_ResultSpec *rs,
int row)
{
- int had_null = GNUNET_NO;
- size_t len;
unsigned int i;
- unsigned int j;
- const char *res;
- void *dst;
- int fnum;
+ int had_null = GNUNET_NO;
- for (i=0; NULL != rs[i].fname; i++)
+ for (i=0; TALER_PQ_RF_END != rs[i].format; i++)
{
- fnum = PQfnumber (result,
- rs[i].fname);
- if (fnum < 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Field `%s' does not exist in result\n",
- rs[i].fname);
- return GNUNET_SYSERR;
- }
+ struct TALER_PQ_ResultSpec *spec;
- /* if a field is null, continue but
- * remember that we now return a different result */
- if (PQgetisnull (result,
- row,
- fnum))
- {
- had_null = GNUNET_YES;
- continue;
- }
- len = PQgetlength (result,
- row,
- fnum);
- if ( (0 != rs[i].dst_size) &&
- (rs[i].dst_size != len) )
+ spec = &rs[i];
+ switch (spec->format)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "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++)
+ case TALER_PQ_RF_FIXED_BLOB:
+ case TALER_PQ_RF_VARSIZE_BLOB:
{
- if (0 == rs[j].dst_size)
+ size_t len;
+ unsigned int j;
+ 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 != 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",
+ 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;
+ if (NULL != rs[j].result_size)
+ *rs[j].result_size = 0;
+ }
+ }
+ return GNUNET_SYSERR;
+ }
+ res = PQgetvalue (result,
+ row,
+ fnum);
+ GNUNET_assert (NULL != res);
+ if (0 == rs[i].dst_size)
{
- GNUNET_free (rs[j].dst);
- rs[j].dst = NULL;
- if (NULL != rs[j].result_size)
- *rs[j].result_size = 0;
+ if (NULL != rs[i].result_size)
+ *rs[i].result_size = len;
+ rs[i].dst_size = len;
+ dst = GNUNET_malloc (len);
+ *((void **) rs[i].dst) = dst;
}
+ else
+ dst = rs[i].dst;
+ memcpy (dst,
+ res,
+ len);
+ break;
}
- return GNUNET_SYSERR;
- }
- res = PQgetvalue (result,
- row,
- fnum);
- GNUNET_assert (NULL != res);
- if (0 == rs[i].dst_size)
- {
- if (NULL != rs[i].result_size)
- *rs[i].result_size = len;
- rs[i].dst_size = len;
- dst = GNUNET_malloc (len);
- *((void **) rs[i].dst) = dst;
+ case TALER_PQ_RF_AMOUNT_NBO:
+ {
+ char *val_name;
+ char *frac_name;
+ char *curr_name;
+ const char *name = spec->fname;
+
+ GNUNET_assert (NULL != rs[i].dst);
+ GNUNET_asprintf (&val_name,
+ "%s_val",
+ name);
+ GNUNET_asprintf (&frac_name,
+ "%s_frac",
+ name);
+ GNUNET_asprintf (&curr_name,
+ "%s_curr",
+ name);
+
+ if (GNUNET_YES !=
+ TALER_PQ_extract_amount_nbo (result,
+ row,
+ val_name,
+ frac_name,
+ curr_name,
+ rs[i].dst))
+ had_null = GNUNET_YES;
+ GNUNET_free (val_name);
+ GNUNET_free (frac_name);
+ GNUNET_free (curr_name);
+ break;
+ }
+ default:
+ GNUNET_assert (0);
+ break;
}
- else
- dst = rs[i].dst;
- memcpy (dst,
- res,
- len);
}
if (GNUNET_YES == had_null)
return GNUNET_NO;