diff options
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 |
commit | 5bf8a16e6a1aae1a59062a3ae3d8c939da0643ab (patch) | |
tree | 563c675c3c7f287fb460d56c394c2deb81af8331 | |
parent | 5ebd19e60b820bb96b4451c366c2f152ab30ff67 (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.h | 253 | ||||
-rw-r--r-- | src/pq/pq.h | 33 | ||||
-rw-r--r-- | src/pq/pq_query_helper.c | 36 | ||||
-rw-r--r-- | src/pq/pq_result_helper.c | 529 | ||||
-rw-r--r-- | src/pq/test_pq.c | 108 |
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); |