gnunet-svn
[Top][All Lists]
Advanced

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

[gnunet] branch master updated (0c4ab7cdd -> 212b47afc)


From: gnunet
Subject: [gnunet] branch master updated (0c4ab7cdd -> 212b47afc)
Date: Fri, 02 Jun 2023 16:19:08 +0200

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

oec pushed a change to branch master
in repository gnunet.

    from 0c4ab7cdd NAMESTORE: Add test to gitignore
     new a901ae121 -pq: slight optimization
     new 5ebd19e60 -pq: slight optimization
     new 5bf8a16e6 pq: Added API to support arrays in query results
     new 212b47afc pq: Added spec-API to support arrays in query results

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/include/gnunet_pq_lib.h | 253 ++++++++++++++++++---
 src/pq/pq.h                 |  33 +++
 src/pq/pq_query_helper.c    |  83 ++-----
 src/pq/pq_result_helper.c   | 529 ++++++++++++++++++++++++++++++++++++++++++++
 src/pq/test_pq.c            | 108 ++++++++-
 5 files changed, 911 insertions(+), 95 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 1a31333d9..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;
 
@@ -860,14 +828,12 @@ qconv_array (
           {
           case array_of_abs_time:
             {
-              const struct GNUNET_TIME_Absolute *abs;
-
-              if (meta->continuous)
-              {
-                abs = (const struct GNUNET_TIME_Absolute *) in;
-                in += sz;
-              }
-              else
+              const struct GNUNET_TIME_Absolute *abs =
+                (const struct GNUNET_TIME_Absolute *) in;
+
+              GNUNET_assert (sizeof(struct GNUNET_TIME_Absolute) == sz);
+
+              if (! meta->continuous)
                 abs = ((const struct GNUNET_TIME_Absolute **) data)[i];
 
               val = abs->abs_value_us;
@@ -875,34 +841,28 @@ qconv_array (
             }
           case array_of_rel_time:
             {
-              const struct GNUNET_TIME_Relative *rel;
-
-              if (meta->continuous)
-              {
-                rel = (const struct GNUNET_TIME_Relative *) in;
-                in += sz;
-              }
-              else
+              const struct GNUNET_TIME_Relative *rel =
+                (const struct GNUNET_TIME_Relative *) in;
+
+              GNUNET_assert (sizeof(struct GNUNET_TIME_Relative) == sz);
+
+              if (! meta->continuous)
                 rel = ((const struct GNUNET_TIME_Relative **) data)[i];
 
               val = rel->rel_value_us;
-
               break;
             }
           case array_of_timestamp:
             {
-              const struct GNUNET_TIME_Timestamp *ts;
-
-              if (meta->continuous)
-              {
-                ts = (const struct GNUNET_TIME_Timestamp *) in;
-                in += sz;
-              }
-              else
+              const struct GNUNET_TIME_Timestamp *ts =
+                (const struct GNUNET_TIME_Timestamp *) in;
+
+              GNUNET_assert (sizeof(struct GNUNET_TIME_Timestamp) == sz);
+
+              if (! meta->continuous)
                 ts = ((const struct GNUNET_TIME_Timestamp **) data)[i];
 
               val = ts->abs_time.abs_value_us;
-
               break;
             }
           default:
@@ -916,6 +876,9 @@ qconv_array (
 
           *(uint64_t *) out = GNUNET_htonll (val);
 
+          if (meta->continuous)
+            in += sz;
+
           break;
         }
       default:
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]