gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet] 02/04: pq: Added API to support arrays in query results


From: gnunet
Subject: [gnunet] 02/04: pq: Added API to support arrays in query results
Date: Fri, 02 Jun 2023 16:19:10 +0200

This is an automated email from the git hooks/post-receive script.

oec pushed a commit to branch master
in repository gnunet.

commit 5bf8a16e6a1aae1a59062a3ae3d8c939da0643ab
Author: Özgür Kesim <oec-taler@kesim.org>
AuthorDate: Fri Jun 2 16:14:32 2023 +0200

    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.
---
 src/include/gnunet_pq_lib.h | 253 ++++++++++++++++++---
 src/pq/pq.h                 |  33 +++
 src/pq/pq_query_helper.c    |  36 +--
 src/pq/pq_result_helper.c   | 529 ++++++++++++++++++++++++++++++++++++++++++++
 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
@@ -106,6 +106,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
@@ -575,38 +575,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.
  *
@@ -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);
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]