summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2023-06-02 16:14:32 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2023-06-02 16:14:32 +0200
commit5bf8a16e6a1aae1a59062a3ae3d8c939da0643ab (patch)
tree563c675c3c7f287fb460d56c394c2deb81af8331
parent5ebd19e60b820bb96b4451c366c2f152ab30ff67 (diff)
pq: Added API to support arrays in query results
NEWS: Added API to support arrays in query results The following functions were added: - GNUNET_PQ_result_spec_array_bool - GNUNET_PQ_result_spec_array_uint16 - GNUNET_PQ_result_spec_array_uint32 - GNUNET_PQ_result_spec_array_uint64 - GNUNET_PQ_result_spec_array_abs_time - GNUNET_PQ_result_spec_array_rel_time - GNUNET_PQ_result_spec_array_timestamp - GNUNET_PQ_result_spec_array_variable_size - GNUNET_PQ_result_spec_array_fixed_size - GNUNET_PQ_result_spec_auto_array_from_type - GNUNET_PQ_result_spec_array_string Tests for these functinos are implemented.
-rw-r--r--src/include/gnunet_pq_lib.h253
-rw-r--r--src/pq/pq.h33
-rw-r--r--src/pq/pq_query_helper.c36
-rw-r--r--src/pq/pq_result_helper.c529
-rw-r--r--src/pq/test_pq.c108
5 files changed, 890 insertions, 69 deletions
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h
index b21c6974f..78eaf0d49 100644
--- a/src/include/gnunet_pq_lib.h
+++ b/src/include/gnunet_pq_lib.h
@@ -131,13 +131,13 @@ GNUNET_PQ_cleanup_query_params_closures (
* End of query parameter specification.
*/
#define GNUNET_PQ_query_param_end \
- { \
- .conv = NULL, \
- .conv_cls = NULL, \
- .data = NULL, \
- .size = 0, \
- .num_params = 0 \
- }
+ { \
+ .conv = NULL, \
+ .conv_cls = NULL, \
+ .data = NULL, \
+ .size = 0, \
+ .num_params = 0 \
+ }
/**
@@ -300,10 +300,10 @@ GNUNET_PQ_query_param_array_bytes_same_size (
* @return query parameter to use
*/
#define GNUNET_PQ_query_param_array_auto_from_type(num, elements, db) \
- GNUNET_PQ_query_param_array_bytes_same_size ((num), \
- (elements), \
- sizeof(*(elements)), \
- (db))
+ GNUNET_PQ_query_param_array_bytes_same_size ((num), \
+ (elements), \
+ sizeof(*(elements)), \
+ (db))
/**
* Generate query parameter for an array of pointers to buffers @a elements,
@@ -333,10 +333,10 @@ GNUNET_PQ_query_param_array_ptrs_bytes_same_size (
* @return query parameter to use
*/
#define GNUNET_PQ_query_param_array_ptrs_auto_from_type(num, elements, db) \
- GNUNET_PQ_query_param_array_ptrs_bytes_same_size ((num), \
- (elements), \
- sizeof(*(elements[0])), \
- (db))
+ GNUNET_PQ_query_param_array_ptrs_bytes_same_size ((num), \
+ (elements), \
+ sizeof(*(elements[0])), \
+ (db))
/**
@@ -376,7 +376,7 @@ GNUNET_PQ_query_param_array_ptrs_string (
* @return query parameter to use
*/
#define GNUNET_PQ_query_param_auto_from_type(x) \
- GNUNET_PQ_query_param_fixed_size ((x), sizeof(*(x)))
+ GNUNET_PQ_query_param_fixed_size ((x), sizeof(*(x)))
/**
* Generate query parameter for an array of absolute time stamps (continuous)
@@ -667,17 +667,17 @@ struct GNUNET_PQ_ResultSpec
* @return array last entry for the result specification to use
*/
#define GNUNET_PQ_result_spec_end \
- { \
- .conv = NULL, \
- .cleaner = NULL, \
- .cls = NULL, \
- .dst = NULL, \
- .dst_size = 0, \
- .fname = NULL, \
- .result_size = NULL, \
- .is_nullable = false, \
- .is_null = NULL \
- }
+ { \
+ .conv = NULL, \
+ .cleaner = NULL, \
+ .cls = NULL, \
+ .dst = NULL, \
+ .dst_size = 0, \
+ .fname = NULL, \
+ .result_size = NULL, \
+ .is_nullable = false, \
+ .is_null = NULL \
+ }
/**
@@ -730,7 +730,7 @@ GNUNET_PQ_result_spec_fixed_size (const char *name,
* @return array entry for the result specification to use
*/
#define GNUNET_PQ_result_spec_auto_from_type(name, dst) \
- GNUNET_PQ_result_spec_fixed_size (name, (dst), sizeof(*(dst)))
+ GNUNET_PQ_result_spec_fixed_size (name, (dst), sizeof(*(dst)))
/**
@@ -876,6 +876,191 @@ struct GNUNET_PQ_ResultSpec
GNUNET_PQ_result_spec_uint64 (const char *name,
uint64_t *u64);
+/**
+ * array of bool expected.
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param[out] num where to store the number of elements in the array @a bools.
+ * @param[out] bools pointer to where to store the result, an array of @a num bool's. Allocated by the function, MUST be freed with GNUNET_free.
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_bool (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ bool **bools);
+
+/**
+ * array of uint16_t expected.
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param[out] num where to store the number of elements in the array @a u16s.
+ * @param[out] dst pointer to where to store the an array of @a num uint16_t's. Allocated by the function, MUST be freed with GNUNET_free.
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_uint16 (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ uint16_t **dst);
+
+/**
+ * array of uint32_t expected.
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param[out] num where to store the number of elements in the array @a u32s.
+ * @param[out] dst pointer to where to store the array of @a num uint32_t's. Allocated by the function, MUST be freed with GNUNET_free.
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_uint32 (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ uint32_t **dst);
+
+/**
+ * array of uint64_t expected.
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param[out] num where to store the number of elements in the array @a u64s.
+ * @param[out] dst pointer to where to store the array of @a num uint64_t's. Allocated by the function, MUST be freed with GNUNET_free.
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_uint64 (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ uint64_t **dst);
+
+
+/**
+ * array of absolute time expected.
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param[out] num where to store the number of elements in the array @a u64s.
+ * @param[out] dst pointer to where to store the array of @a num absolute time. Allocated by the function, MUST be freed with GNUNET_free.
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_abs_time (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ struct GNUNET_TIME_Absolute **dst);
+
+/**
+ * array of relative time expected.
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param[out] num where to store the number of elements in the array @a u64s.
+ * @param[out] dst pointer to where to store the array of @a num relate time. Allocated by the function, MUST be freed with GNUNET_free.
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_rel_time (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ struct GNUNET_TIME_Relative **dst);
+
+/**
+ * array of relative time expected.
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param[out] num where to store the number of elements in the array @a u64s.
+ * @param[out] dst pointer to where to store the array of @a num timestamps. Allocated by the function, MUST be freed with GNUNET_free.
+ * @return array entry for the result specification to use
+ */
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_timestamp (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ struct GNUNET_TIME_Timestamp **dst);
+
+/**
+ * Array of variable-size result expected.
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param[out] num where to store the number of elements
+ * @param[out] sizes where to store the @a num size's of byte-buffers in @a dst
+ * @param[out] dst where to store the continuous array of @a num byte-buffers , allocated
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_variable_size (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ size_t **sizes,
+ void **dst);
+
+
+/**
+ * Array of fixed-size result expected.
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param size number of bytes expected in each element of @a dst
+ * @param[out] num where to store the number of elements
+ * @param[out] dst where to store the results, an continuous array of fixed-size elements
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_fixed_size (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t size,
+ size_t *num,
+ void **dst);
+
+
+/**
+ * We expect a fixed-size result, with size determined by the type of `* dst`
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param num pointer to where to store the number of elements
+ * @param dst pointer to where to store the results, type fits expected result size
+ * @return array entry for the result specification to use
+ */
+#define GNUNET_PQ_result_spec_auto_array_from_type(db, name, num, dst) \
+ GNUNET_PQ_result_spec_array_fixed_size ( \
+ (db), \
+ (name), \
+ sizeof(*(dst)), \
+ (num), \
+ (void *) &(dst))
+
+
+/**
+ * Array of 0-terminated strings expected.
+ *
+ * @param db Database context, needed for OID lookup for the correct type
+ * @param name name of the field in the table
+ * @param[out] num where to store the number of elements
+ * @param[out] dst where to store the allocated continous array of @a num 0-terminated strings
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_string (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ char **dst);
/* ************************* pq.c functions ************************ */
@@ -1050,9 +1235,9 @@ struct GNUNET_PQ_PreparedStatement
* Terminator for prepared statement list.
*/
#define GNUNET_PQ_PREPARED_STATEMENT_END \
- { \
- NULL, NULL \
- }
+ { \
+ NULL, NULL \
+ }
/**
@@ -1122,9 +1307,9 @@ struct GNUNET_PQ_ExecuteStatement
* Terminator for executable statement list.
*/
#define GNUNET_PQ_EXECUTE_STATEMENT_END \
- { \
- NULL, GNUNET_SYSERR \
- }
+ { \
+ NULL, GNUNET_SYSERR \
+ }
/**
diff --git a/src/pq/pq.h b/src/pq/pq.h
index 404cc4f3b..0c011a6ef 100644
--- a/src/pq/pq.h
+++ b/src/pq/pq.h
@@ -107,6 +107,39 @@ struct GNUNET_PQ_Context
/**
+ * Internal types that are supported as array types.
+ */
+
+enum array_types
+{
+ array_of_bool,
+ array_of_uint16,
+ array_of_uint32,
+ array_of_uint64,
+ array_of_byte, /* buffers of (char *), (void *), ... */
+ array_of_string, /* NULL-terminated (char *) */
+ array_of_abs_time,
+ array_of_rel_time,
+ array_of_timestamp,
+ array_of_MAX, /* must be last */
+};
+
+/**
+ * the header for a postgresql array in binary format. note that this a
+ * simplified special case of the general structure (which contains pointers),
+ * as we only support one-dimensional arrays.
+ */
+struct pq_array_header
+{
+ uint32_t ndim; /* number of dimensions. we only support ndim = 1 */
+ uint32_t has_null;
+ uint32_t oid;
+ uint32_t dim; /* size of the array */
+ uint32_t lbound; /* index value of first element in the db (default: 1). */
+} __attribute__((packed));
+
+
+/**
* Internal API. Reconnect should re-register notifications
* after a disconnect.
*
diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c
index 0d9371bd5..f57fb338c 100644
--- a/src/pq/pq_query_helper.c
+++ b/src/pq/pq_query_helper.c
@@ -576,38 +576,6 @@ GNUNET_PQ_query_param_timestamp_nbo (
/**
- * The header for a Postgresql array in binary format. Note that this a
- * simplified special case of the general structure (which contains pointers),
- * as we only support one-dimensional arrays.
- */
-struct pq_array_header
-{
- uint32_t ndim; /* Number of dimensions. We only support ndim = 1 */
- uint32_t has_null;
- uint32_t oid;
- uint32_t dim; /* Size of the array */
- uint32_t lbound; /* Index value of first element in the DB (default: 1). */
-} __attribute__((packed));
-
-/**
- * Internal types that are supported as array types.
- */
-
-enum array_types
-{
- array_of_bool,
- array_of_uint16,
- array_of_uint32,
- array_of_uint64,
- array_of_byte, /* buffers of (char *), (void *), ... */
- array_of_string, /* NULL-terminated (char *) */
- array_of_abs_time,
- array_of_rel_time,
- array_of_timestamp,
- array_of_MAX, /* must be last */
-};
-
-/**
* Closure for the array type handlers.
*
* May contain sizes information for the data, given (and handled) by the
@@ -631,8 +599,8 @@ struct qconv_array_cls
/**
* If true, the array parameter to the data pointer to the qconv_array is a
- * continuous byte array of data, either with @a same_size each or sizes provided bytes
- * by @a sizes;
+ * continuous byte array of data, either with @a same_size each or sizes
+ * provided bytes by @a sizes;
*/
bool continuous;
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
index f945c5d2e..808445b3b 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -22,9 +22,12 @@
* @brief functions to extract result values
* @author Christian Grothoff
*/
+#include "gnunet_common.h"
+#include "gnunet_time_lib.h"
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_pq_lib.h"
+#include "pq.h"
struct GNUNET_PQ_ResultSpec
@@ -1117,4 +1120,530 @@ GNUNET_PQ_result_spec_uint64 (const char *name,
}
+/**
+ * Closure for the array result specifications. Contains type information
+ * for the generic parser extract_array_generic and out-pointers for the results.
+ */
+struct array_result_cls
+{
+ /* Oid of the expected type, must match the oid in the header of the PQResult struct */
+ Oid oid;
+
+ /* Target type */
+ enum array_types typ;
+
+ /* If not 0, defines the expected size of each entry */
+ size_t same_size;
+
+ /* Out-pointer to write the number of elements in the array */
+ size_t *num;
+
+ /* Out-pointer. If @a typ is array_of_byte and @a same_size is 0,
+ * allocate and put the array of @a num sizes here. NULL otherwise */
+ size_t **sizes;
+};
+
+
+/**
+ * Extract data from a Postgres database @a result as array of a specific type
+ * from row @a row. The type information and optionally additional
+ * out-parameters are given in @a cls which is of type array_result_cls.
+ *
+ * @param cls closure of type array_result_cls
+ * @param result where to extract data from
+ * @param row 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_SYSERR if a result was invalid (non-existing field or NULL)
+ */
+static enum GNUNET_GenericReturnValue
+extract_array_generic (
+ void *cls,
+ PGresult *result,
+ int row,
+ const char *fname,
+ size_t *dst_size,
+ void *dst)
+{
+ const struct array_result_cls *info = cls;
+ int data_sz;
+ char *data;
+ void *out = NULL;
+ struct pq_array_header header;
+ int col_num;
+
+ GNUNET_assert (NULL != dst);
+ *((void **) dst) = NULL;
+
+ #define FAIL_IF(cond) \
+ do { \
+ if ((cond)) \
+ { \
+ GNUNET_break (! (cond)); \
+ goto FAIL; \
+ } \
+ } while(0)
+
+ col_num = PQfnumber (result, fname);
+ FAIL_IF (0 > col_num);
+
+ data_sz = PQgetlength (result, row, col_num);
+ FAIL_IF (0 > data_sz);
+ FAIL_IF (sizeof(header) > (size_t) data_sz);
+
+ data = PQgetvalue (result, row, col_num);
+ FAIL_IF (NULL == data);
+
+ {
+ struct pq_array_header *h =
+ (struct pq_array_header *) data;
+
+ header.ndim = ntohl (h->ndim);
+ header.has_null = ntohl (h->has_null);
+ header.oid = ntohl (h->oid);
+ header.dim = ntohl (h->dim);
+ header.lbound = ntohl (h->lbound);
+
+ FAIL_IF (1 != header.ndim);
+ FAIL_IF ((0 > header.dim) || (INT_MAX == header.dim));
+ FAIL_IF (0 != header.has_null);
+ FAIL_IF (1 != header.lbound);
+ FAIL_IF (info->oid != header.oid);
+ }
+
+ *info->num = header.dim;
+ switch (info->typ)
+ {
+ case array_of_bool:
+ if (NULL != dst_size)
+ *dst_size = sizeof(bool) * (*info->num);
+ out = GNUNET_new_array (*info->num, bool);
+ break;
+ case array_of_uint16:
+ if (NULL != dst_size)
+ *dst_size = sizeof(uint16_t) * (*info->num);
+ out = GNUNET_new_array (*info->num, uint16_t);
+ break;
+ case array_of_uint32:
+ if (NULL != dst_size)
+ *dst_size = sizeof(uint32_t) * (*info->num);
+ out = GNUNET_new_array (*info->num, uint32_t);
+ break;
+ case array_of_uint64:
+ if (NULL != dst_size)
+ *dst_size = sizeof(uint64_t) * (*info->num);
+ out = GNUNET_new_array (*info->num, uint64_t);
+ break;
+ case array_of_abs_time:
+ if (NULL != dst_size)
+ *dst_size = sizeof(struct GNUNET_TIME_Absolute) * (*info->num);
+ out = GNUNET_new_array (*info->num, struct GNUNET_TIME_Absolute);
+ break;
+ case array_of_rel_time:
+ if (NULL != dst_size)
+ *dst_size = sizeof(struct GNUNET_TIME_Relative) * (*info->num);
+ out = GNUNET_new_array (*info->num, struct GNUNET_TIME_Relative);
+ break;
+ case array_of_timestamp:
+ if (NULL != dst_size)
+ *dst_size = sizeof(struct GNUNET_TIME_Timestamp) * (*info->num);
+ out = GNUNET_new_array (*info->num, struct GNUNET_TIME_Timestamp);
+ break;
+ case array_of_byte:
+ if (0 == info->same_size)
+ *info->sizes = GNUNET_new_array (header.dim, size_t);
+ /* fallthrough */
+ case array_of_string:
+ {
+ size_t total = 0;
+ bool is_string = (array_of_string == info->typ);
+
+ /* first, calculate total size required for allocation */
+ {
+ char *ptr = data + sizeof(header);
+ for (uint32_t i = 0; i < header.dim; i++)
+ {
+ uint32_t sz;
+
+ sz = ntohl (*(uint32_t *) ptr);
+ sz += is_string ? 1 : 0;
+ total += sz;
+ ptr += sizeof(uint32_t);
+ ptr += sz;
+
+ if ((! is_string) &&
+ (0 == info->same_size))
+ (*info->sizes)[i] = sz;
+
+ FAIL_IF ((0 != info->same_size) &&
+ (sz != info->same_size));
+ FAIL_IF (total < sz);
+ }
+ }
+
+ if (NULL != dst_size)
+ *dst_size = total;
+
+ if (0 < total)
+ out = GNUNET_malloc (total);
+
+ break;
+ }
+ default:
+ FAIL_IF (1 != 0);
+ }
+
+ *((void **) dst) = out;
+
+ /* copy data */
+ {
+ char *in = data + sizeof(header);
+
+ for (uint32_t i = 0; i < header.dim; i++)
+ {
+ size_t sz = ntohl (*(uint32_t *) in);
+ in += sizeof(uint32_t);
+
+ switch (info->typ)
+ {
+ case array_of_bool:
+ FAIL_IF (sz != sizeof(bool));
+ *(bool *) out = *(bool *) in;
+ break;
+ case array_of_uint16:
+ FAIL_IF (sz != sizeof(uint16_t));
+ *(uint16_t *) out = ntohs (*(uint16_t *) in);
+ break;
+ case array_of_uint32:
+ FAIL_IF (sz != sizeof(uint32_t));
+ *(uint32_t *) out = ntohl (*(uint32_t *) in);
+ break;
+ case array_of_uint64:
+ FAIL_IF (sz != sizeof(uint64_t));
+ *(uint64_t *) out = GNUNET_ntohll (*(uint64_t *) in);
+ break;
+ case array_of_abs_time:
+ case array_of_rel_time:
+ case array_of_timestamp:
+ FAIL_IF (sz != sizeof(uint64_t));
+ {
+ uint64_t val = GNUNET_ntohll (*(uint64_t *) in);
+ switch (info->typ)
+ {
+ case array_of_abs_time:
+ ((struct GNUNET_TIME_Absolute *) out)->abs_value_us = val;
+ break;
+ case array_of_rel_time:
+ ((struct GNUNET_TIME_Relative *) out)->rel_value_us = val;
+ break;
+ case array_of_timestamp:
+ ((struct GNUNET_TIME_Timestamp *) out)->abs_time.abs_value_us = val;
+ break;
+ default:
+ FAIL_IF (1 != 0);
+ }
+ }
+ break;
+ case array_of_byte:
+ case array_of_string:
+ GNUNET_memcpy (out, in, sz);
+ break;
+ default:
+ FAIL_IF (1 != 0);
+ }
+
+ in += sz;
+ out += sz;
+ out += (array_of_string == info->typ) ? 1 : 0;
+ }
+ }
+
+ return GNUNET_OK;
+
+FAIL:
+ GNUNET_free (*(void **) dst);
+ return GNUNET_SYSERR;
+ #undef FAIL_IF
+}
+
+
+/**
+ * Cleanup of the data and closure of an array spec.
+ */
+static void
+array_cleanup (void *cls,
+ void *rd)
+{
+
+ struct array_result_cls *info = cls;
+ void **dst = rd;
+
+ if ((array_of_byte == info->typ) &&
+ (0 == info->same_size) &&
+ (NULL != info->sizes))
+ GNUNET_free (*(info->sizes));
+
+ GNUNET_free (cls);
+ GNUNET_free (*dst);
+ *dst = NULL;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_bool (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ bool **dst)
+{
+ struct array_result_cls *info =
+ GNUNET_new (struct array_result_cls);
+
+ info->num = num;
+ info->typ = array_of_bool;
+ info->oid = db->oids[GNUNET_PQ_DATATYPE_BOOL];
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) dst,
+ .fname = name,
+ .cls = info
+ };
+ return res;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_uint16 (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ uint16_t **dst)
+{
+ struct array_result_cls *info =
+ GNUNET_new (struct array_result_cls);
+
+ info->num = num;
+ info->typ = array_of_uint16;
+ info->oid = db->oids[GNUNET_PQ_DATATYPE_INT2];
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) dst,
+ .fname = name,
+ .cls = info
+ };
+ return res;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_uint32 (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ uint32_t **dst)
+{
+ struct array_result_cls *info =
+ GNUNET_new (struct array_result_cls);
+
+ info->num = num;
+ info->typ = array_of_uint32;
+ info->oid = db->oids[GNUNET_PQ_DATATYPE_INT4];
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) dst,
+ .fname = name,
+ .cls = info
+ };
+ return res;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_uint64 (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ uint64_t **dst)
+{
+ struct array_result_cls *info =
+ GNUNET_new (struct array_result_cls);
+
+ info->num = num;
+ info->typ = array_of_uint64;
+ info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) dst,
+ .fname = name,
+ .cls = info
+ };
+ return res;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_abs_time (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ struct GNUNET_TIME_Absolute **dst)
+{
+ struct array_result_cls *info =
+ GNUNET_new (struct array_result_cls);
+
+ info->num = num;
+ info->typ = array_of_abs_time;
+ info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) dst,
+ .fname = name,
+ .cls = info
+ };
+ return res;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_rel_time (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ struct GNUNET_TIME_Relative **dst)
+{
+ struct array_result_cls *info =
+ GNUNET_new (struct array_result_cls);
+
+ info->num = num;
+ info->typ = array_of_rel_time;
+ info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) dst,
+ .fname = name,
+ .cls = info
+ };
+ return res;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_timestamp (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ struct GNUNET_TIME_Timestamp **dst)
+{
+ struct array_result_cls *info =
+ GNUNET_new (struct array_result_cls);
+
+ info->num = num;
+ info->typ = array_of_timestamp;
+ info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) dst,
+ .fname = name,
+ .cls = info
+ };
+ return res;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_variable_size (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ size_t **sizes,
+ void **dst)
+{
+ struct array_result_cls *info =
+ GNUNET_new (struct array_result_cls);
+
+ info->num = num;
+ info->sizes = sizes;
+ info->typ = array_of_byte;
+ info->oid = db->oids[GNUNET_PQ_DATATYPE_BYTEA];
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) dst,
+ .fname = name,
+ .cls = info
+ };
+ return res;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_fixed_size (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t size,
+ size_t *num,
+ void **dst)
+{
+ struct array_result_cls *info =
+ GNUNET_new (struct array_result_cls);
+
+ info->num = num;
+ info->same_size = size;
+ info->typ = array_of_byte;
+ info->oid = db->oids[GNUNET_PQ_DATATYPE_BYTEA];
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) dst,
+ .fname = name,
+ .cls = info
+ };
+ return res;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_array_string (
+ const struct GNUNET_PQ_Context *db,
+ const char *name,
+ size_t *num,
+ char **dst)
+{
+ struct array_result_cls *info =
+ GNUNET_new (struct array_result_cls);
+
+ info->num = num;
+ info->typ = array_of_string;
+ info->oid = db->oids[GNUNET_PQ_DATATYPE_VARCHAR];
+
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = extract_array_generic,
+ .cleaner = array_cleanup,
+ .dst = (void *) dst,
+ .fname = name,
+ .cls = info
+ };
+ return res;
+}
+
+
/* end of pq_result_helper.c */
diff --git a/src/pq/test_pq.c b/src/pq/test_pq.c
index a6354c7c0..c97474814 100644
--- a/src/pq/test_pq.c
+++ b/src/pq/test_pq.c
@@ -23,6 +23,7 @@
* @author Christian Grothoff <christian@grothoff.org>
*/
#include "gnunet_common.h"
+#include "gnunet_pq_lib.h"
#include "gnunet_time_lib.h"
#include "platform.h"
#include "pq.h"
@@ -154,7 +155,7 @@ run_queries (struct GNUNET_PQ_Context *db)
uint16_t ai2[3] = {42, 0x0001, 0xFFFF};
uint32_t ai4[3] = {42, 0x00010000, 0xFFFFFFFF};
uint64_t ai8[3] = {42, 0x0001000000000000, 0xFFFFFFFFFFFFFFFF};
- const char *as[] = {"foo", "bar", "buz"};
+ const char *as[] = {"foo", "bar", "buzz"};
const struct GNUNET_TIME_Absolute ata[2] = {GNUNET_TIME_absolute_get (),
GNUNET_TIME_absolute_get ()};
const struct GNUNET_TIME_Relative atr[2] = {GNUNET_TIME_relative_get_hour_ (),
@@ -208,6 +209,27 @@ run_queries (struct GNUNET_PQ_Context *db)
GNUNET_PQ_query_param_end
};
bool got_null = false;
+ size_t num_bool;
+ bool *arr_bools;
+ size_t num_u16;
+ uint16_t *arr_u16;
+ size_t num_u32;
+ uint32_t *arr_u32;
+ size_t num_u64;
+ uint64_t *arr_u64;
+ size_t num_abs;
+ struct GNUNET_TIME_Absolute *arr_abs;
+ size_t num_rel;
+ struct GNUNET_TIME_Relative *arr_rel;
+ size_t num_tstmp;
+ struct GNUNET_TIME_Timestamp *arr_tstmp;
+ size_t num_str;
+ char *arr_str;
+ size_t num_hash;
+ struct GNUNET_HashCode *arr_hash;
+ size_t num_buf;
+ void *arr_buf;
+ size_t *sz_buf;
struct GNUNET_PQ_ResultSpec results_select[] = {
GNUNET_PQ_result_spec_rsa_public_key ("pub", &pub2),
GNUNET_PQ_result_spec_rsa_signature ("sig", &sig2),
@@ -221,6 +243,47 @@ run_queries (struct GNUNET_PQ_Context *db)
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_uint64 ("unn", &uzzz),
&got_null),
+ GNUNET_PQ_result_spec_array_bool (db,
+ "arr_bool",
+ &num_bool,
+ &arr_bools),
+ GNUNET_PQ_result_spec_array_uint16 (db,
+ "arr_int2",
+ &num_u16,
+ &arr_u16),
+ GNUNET_PQ_result_spec_array_uint32 (db,
+ "arr_int4",
+ &num_u32,
+ &arr_u32),
+ GNUNET_PQ_result_spec_array_uint64 (db,
+ "arr_int8",
+ &num_u64,
+ &arr_u64),
+ GNUNET_PQ_result_spec_array_abs_time (db,
+ "arr_abs_time",
+ &num_abs,
+ &arr_abs),
+ GNUNET_PQ_result_spec_array_rel_time (db,
+ "arr_rel_time",
+ &num_rel,
+ &arr_rel),
+ GNUNET_PQ_result_spec_array_timestamp (db,
+ "arr_timestamp",
+ &num_tstmp,
+ &arr_tstmp),
+ GNUNET_PQ_result_spec_auto_array_from_type (db,
+ "arr_bytea",
+ &num_hash,
+ arr_hash),
+ GNUNET_PQ_result_spec_array_variable_size (db,
+ "arr_bytea",
+ &num_buf,
+ &sz_buf,
+ &arr_buf),
+ GNUNET_PQ_result_spec_array_string (db,
+ "arr_varchar",
+ &num_str,
+ &arr_str),
GNUNET_PQ_result_spec_end
};
@@ -278,6 +341,49 @@ run_queries (struct GNUNET_PQ_Context *db)
GNUNET_break (64 == u642);
GNUNET_break (42 == uzzz);
GNUNET_break (got_null);
+
+ /* Check arrays */
+ {
+ GNUNET_break (num_bool == 5);
+ GNUNET_break (arr_bools[0]);
+ GNUNET_break (! arr_bools[1]);
+ GNUNET_break (! arr_bools[2]);
+ GNUNET_break (arr_bools[3]);
+ GNUNET_break (! arr_bools[4]);
+
+ GNUNET_break (num_u16 == 3);
+ GNUNET_break (arr_u16[0] == 42);
+ GNUNET_break (arr_u16[1] == 0x0001);
+ GNUNET_break (arr_u16[2] == 0xFFFF);
+
+ GNUNET_break (num_u32 == 3);
+ GNUNET_break (arr_u32[0] == 42);
+ GNUNET_break (arr_u32[1] == 0x00010000);
+ GNUNET_break (arr_u32[2] == 0xFFFFFFFF);
+
+ GNUNET_break (num_u64 == 3);
+ GNUNET_break (arr_u64[0] == 42);
+ GNUNET_break (arr_u64[1] == 0x0001000000000000);
+ GNUNET_break (arr_u64[2] == 0xFFFFFFFFFFFFFFFF);
+
+ GNUNET_break (num_str == 3);
+ GNUNET_break (0 == strcmp (arr_str, "foo"));
+ GNUNET_break (0 == strcmp (arr_str + 4, "bar"));
+ GNUNET_break (0 == strcmp (arr_str + 8, "buzz"));
+
+ GNUNET_break (num_hash == 3);
+ GNUNET_break (0 == GNUNET_memcmp (&arr_hash[0], &arr_hash[1]));
+ GNUNET_break (0 == GNUNET_memcmp (&arr_hash[1], &arr_hash[2]));
+
+ GNUNET_break (num_buf == 3);
+ {
+ char *ptr = arr_buf;
+ GNUNET_break (0 == memcmp (ptr, &ptr[sz_buf[0]], sz_buf[0]));
+ ptr += sz_buf[0];
+ GNUNET_break (0 == memcmp (ptr, &ptr[sz_buf[1]], sz_buf[1]));
+ }
+ }
+
GNUNET_PQ_cleanup_result (results_select);
PQclear (result);