aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2023-06-02 16:14:32 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2023-06-02 16:14:32 +0200
commit5bf8a16e6a1aae1a59062a3ae3d8c939da0643ab (patch)
tree563c675c3c7f287fb460d56c394c2deb81af8331
parent5ebd19e60b820bb96b4451c366c2f152ab30ff67 (diff)
downloadgnunet-5bf8a16e6a1aae1a59062a3ae3d8c939da0643ab.tar.gz
gnunet-5bf8a16e6a1aae1a59062a3ae3d8c939da0643ab.zip
pq: Added API to support arrays in query results
NEWS: Added API to support arrays in query results The following functions were added: - GNUNET_PQ_result_spec_array_bool - GNUNET_PQ_result_spec_array_uint16 - GNUNET_PQ_result_spec_array_uint32 - GNUNET_PQ_result_spec_array_uint64 - GNUNET_PQ_result_spec_array_abs_time - GNUNET_PQ_result_spec_array_rel_time - GNUNET_PQ_result_spec_array_timestamp - GNUNET_PQ_result_spec_array_variable_size - GNUNET_PQ_result_spec_array_fixed_size - GNUNET_PQ_result_spec_auto_array_from_type - GNUNET_PQ_result_spec_array_string Tests for these functinos are implemented.
-rw-r--r--src/include/gnunet_pq_lib.h253
-rw-r--r--src/pq/pq.h33
-rw-r--r--src/pq/pq_query_helper.c36
-rw-r--r--src/pq/pq_result_helper.c529
-rw-r--r--src/pq/test_pq.c108
5 files changed, 890 insertions, 69 deletions
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h
index b21c6974f..78eaf0d49 100644
--- a/src/include/gnunet_pq_lib.h
+++ b/src/include/gnunet_pq_lib.h
@@ -131,13 +131,13 @@ GNUNET_PQ_cleanup_query_params_closures (
131 * End of query parameter specification. 131 * End of query parameter specification.
132 */ 132 */
133#define GNUNET_PQ_query_param_end \ 133#define GNUNET_PQ_query_param_end \
134 { \ 134 { \
135 .conv = NULL, \ 135 .conv = NULL, \
136 .conv_cls = NULL, \ 136 .conv_cls = NULL, \
137 .data = NULL, \ 137 .data = NULL, \
138 .size = 0, \ 138 .size = 0, \
139 .num_params = 0 \ 139 .num_params = 0 \
140 } 140 }
141 141
142 142
143/** 143/**
@@ -300,10 +300,10 @@ GNUNET_PQ_query_param_array_bytes_same_size (
300 * @return query parameter to use 300 * @return query parameter to use
301 */ 301 */
302#define GNUNET_PQ_query_param_array_auto_from_type(num, elements, db) \ 302#define GNUNET_PQ_query_param_array_auto_from_type(num, elements, db) \
303 GNUNET_PQ_query_param_array_bytes_same_size ((num), \ 303 GNUNET_PQ_query_param_array_bytes_same_size ((num), \
304 (elements), \ 304 (elements), \
305 sizeof(*(elements)), \ 305 sizeof(*(elements)), \
306 (db)) 306 (db))
307 307
308/** 308/**
309 * Generate query parameter for an array of pointers to buffers @a elements, 309 * 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 (
333 * @return query parameter to use 333 * @return query parameter to use
334 */ 334 */
335#define GNUNET_PQ_query_param_array_ptrs_auto_from_type(num, elements, db) \ 335#define GNUNET_PQ_query_param_array_ptrs_auto_from_type(num, elements, db) \
336 GNUNET_PQ_query_param_array_ptrs_bytes_same_size ((num), \ 336 GNUNET_PQ_query_param_array_ptrs_bytes_same_size ((num), \
337 (elements), \ 337 (elements), \
338 sizeof(*(elements[0])), \ 338 sizeof(*(elements[0])), \
339 (db)) 339 (db))
340 340
341 341
342/** 342/**
@@ -376,7 +376,7 @@ GNUNET_PQ_query_param_array_ptrs_string (
376 * @return query parameter to use 376 * @return query parameter to use
377 */ 377 */
378#define GNUNET_PQ_query_param_auto_from_type(x) \ 378#define GNUNET_PQ_query_param_auto_from_type(x) \
379 GNUNET_PQ_query_param_fixed_size ((x), sizeof(*(x))) 379 GNUNET_PQ_query_param_fixed_size ((x), sizeof(*(x)))
380 380
381/** 381/**
382 * Generate query parameter for an array of absolute time stamps (continuous) 382 * Generate query parameter for an array of absolute time stamps (continuous)
@@ -667,17 +667,17 @@ struct GNUNET_PQ_ResultSpec
667 * @return array last entry for the result specification to use 667 * @return array last entry for the result specification to use
668 */ 668 */
669#define GNUNET_PQ_result_spec_end \ 669#define GNUNET_PQ_result_spec_end \
670 { \ 670 { \
671 .conv = NULL, \ 671 .conv = NULL, \
672 .cleaner = NULL, \ 672 .cleaner = NULL, \
673 .cls = NULL, \ 673 .cls = NULL, \
674 .dst = NULL, \ 674 .dst = NULL, \
675 .dst_size = 0, \ 675 .dst_size = 0, \
676 .fname = NULL, \ 676 .fname = NULL, \
677 .result_size = NULL, \ 677 .result_size = NULL, \
678 .is_nullable = false, \ 678 .is_nullable = false, \
679 .is_null = NULL \ 679 .is_null = NULL \
680 } 680 }
681 681
682 682
683/** 683/**
@@ -730,7 +730,7 @@ GNUNET_PQ_result_spec_fixed_size (const char *name,
730 * @return array entry for the result specification to use 730 * @return array entry for the result specification to use
731 */ 731 */
732#define GNUNET_PQ_result_spec_auto_from_type(name, dst) \ 732#define GNUNET_PQ_result_spec_auto_from_type(name, dst) \
733 GNUNET_PQ_result_spec_fixed_size (name, (dst), sizeof(*(dst))) 733 GNUNET_PQ_result_spec_fixed_size (name, (dst), sizeof(*(dst)))
734 734
735 735
736/** 736/**
@@ -876,6 +876,191 @@ struct GNUNET_PQ_ResultSpec
876GNUNET_PQ_result_spec_uint64 (const char *name, 876GNUNET_PQ_result_spec_uint64 (const char *name,
877 uint64_t *u64); 877 uint64_t *u64);
878 878
879/**
880 * array of bool expected.
881 *
882 * @param db Database context, needed for OID lookup for the correct type
883 * @param name name of the field in the table
884 * @param[out] num where to store the number of elements in the array @a bools.
885 * @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.
886 * @return array entry for the result specification to use
887 */
888struct GNUNET_PQ_ResultSpec
889GNUNET_PQ_result_spec_array_bool (
890 const struct GNUNET_PQ_Context *db,
891 const char *name,
892 size_t *num,
893 bool **bools);
894
895/**
896 * array of uint16_t expected.
897 *
898 * @param db Database context, needed for OID lookup for the correct type
899 * @param name name of the field in the table
900 * @param[out] num where to store the number of elements in the array @a u16s.
901 * @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.
902 * @return array entry for the result specification to use
903 */
904struct GNUNET_PQ_ResultSpec
905GNUNET_PQ_result_spec_array_uint16 (
906 const struct GNUNET_PQ_Context *db,
907 const char *name,
908 size_t *num,
909 uint16_t **dst);
910
911/**
912 * array of uint32_t expected.
913 *
914 * @param db Database context, needed for OID lookup for the correct type
915 * @param name name of the field in the table
916 * @param[out] num where to store the number of elements in the array @a u32s.
917 * @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.
918 * @return array entry for the result specification to use
919 */
920struct GNUNET_PQ_ResultSpec
921GNUNET_PQ_result_spec_array_uint32 (
922 const struct GNUNET_PQ_Context *db,
923 const char *name,
924 size_t *num,
925 uint32_t **dst);
926
927/**
928 * array of uint64_t expected.
929 *
930 * @param db Database context, needed for OID lookup for the correct type
931 * @param name name of the field in the table
932 * @param[out] num where to store the number of elements in the array @a u64s.
933 * @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.
934 * @return array entry for the result specification to use
935 */
936struct GNUNET_PQ_ResultSpec
937GNUNET_PQ_result_spec_array_uint64 (
938 const struct GNUNET_PQ_Context *db,
939 const char *name,
940 size_t *num,
941 uint64_t **dst);
942
943
944/**
945 * array of absolute time expected.
946 *
947 * @param db Database context, needed for OID lookup for the correct type
948 * @param name name of the field in the table
949 * @param[out] num where to store the number of elements in the array @a u64s.
950 * @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.
951 * @return array entry for the result specification to use
952 */
953struct GNUNET_PQ_ResultSpec
954GNUNET_PQ_result_spec_array_abs_time (
955 const struct GNUNET_PQ_Context *db,
956 const char *name,
957 size_t *num,
958 struct GNUNET_TIME_Absolute **dst);
959
960/**
961 * array of relative time expected.
962 *
963 * @param db Database context, needed for OID lookup for the correct type
964 * @param name name of the field in the table
965 * @param[out] num where to store the number of elements in the array @a u64s.
966 * @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.
967 * @return array entry for the result specification to use
968 */
969struct GNUNET_PQ_ResultSpec
970GNUNET_PQ_result_spec_array_rel_time (
971 const struct GNUNET_PQ_Context *db,
972 const char *name,
973 size_t *num,
974 struct GNUNET_TIME_Relative **dst);
975
976/**
977 * array of relative time expected.
978 *
979 * @param db Database context, needed for OID lookup for the correct type
980 * @param name name of the field in the table
981 * @param[out] num where to store the number of elements in the array @a u64s.
982 * @param[out] dst pointer to where to store the array of @a num timestamps. Allocated by the function, MUST be freed with GNUNET_free.
983 * @return array entry for the result specification to use
984 */
985
986struct GNUNET_PQ_ResultSpec
987GNUNET_PQ_result_spec_array_timestamp (
988 const struct GNUNET_PQ_Context *db,
989 const char *name,
990 size_t *num,
991 struct GNUNET_TIME_Timestamp **dst);
992
993/**
994 * Array of variable-size result expected.
995 *
996 * @param db Database context, needed for OID lookup for the correct type
997 * @param name name of the field in the table
998 * @param[out] num where to store the number of elements
999 * @param[out] sizes where to store the @a num size's of byte-buffers in @a dst
1000 * @param[out] dst where to store the continuous array of @a num byte-buffers , allocated
1001 * @return array entry for the result specification to use
1002 */
1003struct GNUNET_PQ_ResultSpec
1004GNUNET_PQ_result_spec_array_variable_size (
1005 const struct GNUNET_PQ_Context *db,
1006 const char *name,
1007 size_t *num,
1008 size_t **sizes,
1009 void **dst);
1010
1011
1012/**
1013 * Array of fixed-size result expected.
1014 *
1015 * @param db Database context, needed for OID lookup for the correct type
1016 * @param name name of the field in the table
1017 * @param size number of bytes expected in each element of @a dst
1018 * @param[out] num where to store the number of elements
1019 * @param[out] dst where to store the results, an continuous array of fixed-size elements
1020 * @return array entry for the result specification to use
1021 */
1022struct GNUNET_PQ_ResultSpec
1023GNUNET_PQ_result_spec_array_fixed_size (
1024 const struct GNUNET_PQ_Context *db,
1025 const char *name,
1026 size_t size,
1027 size_t *num,
1028 void **dst);
1029
1030
1031/**
1032 * We expect a fixed-size result, with size determined by the type of `* dst`
1033 *
1034 * @param db Database context, needed for OID lookup for the correct type
1035 * @param name name of the field in the table
1036 * @param num pointer to where to store the number of elements
1037 * @param dst pointer to where to store the results, type fits expected result size
1038 * @return array entry for the result specification to use
1039 */
1040#define GNUNET_PQ_result_spec_auto_array_from_type(db, name, num, dst) \
1041 GNUNET_PQ_result_spec_array_fixed_size ( \
1042 (db), \
1043 (name), \
1044 sizeof(*(dst)), \
1045 (num), \
1046 (void *) &(dst))
1047
1048
1049/**
1050 * Array of 0-terminated strings expected.
1051 *
1052 * @param db Database context, needed for OID lookup for the correct type
1053 * @param name name of the field in the table
1054 * @param[out] num where to store the number of elements
1055 * @param[out] dst where to store the allocated continous array of @a num 0-terminated strings
1056 * @return array entry for the result specification to use
1057 */
1058struct GNUNET_PQ_ResultSpec
1059GNUNET_PQ_result_spec_array_string (
1060 const struct GNUNET_PQ_Context *db,
1061 const char *name,
1062 size_t *num,
1063 char **dst);
879 1064
880/* ************************* pq.c functions ************************ */ 1065/* ************************* pq.c functions ************************ */
881 1066
@@ -1050,9 +1235,9 @@ struct GNUNET_PQ_PreparedStatement
1050 * Terminator for prepared statement list. 1235 * Terminator for prepared statement list.
1051 */ 1236 */
1052#define GNUNET_PQ_PREPARED_STATEMENT_END \ 1237#define GNUNET_PQ_PREPARED_STATEMENT_END \
1053 { \ 1238 { \
1054 NULL, NULL \ 1239 NULL, NULL \
1055 } 1240 }
1056 1241
1057 1242
1058/** 1243/**
@@ -1122,9 +1307,9 @@ struct GNUNET_PQ_ExecuteStatement
1122 * Terminator for executable statement list. 1307 * Terminator for executable statement list.
1123 */ 1308 */
1124#define GNUNET_PQ_EXECUTE_STATEMENT_END \ 1309#define GNUNET_PQ_EXECUTE_STATEMENT_END \
1125 { \ 1310 { \
1126 NULL, GNUNET_SYSERR \ 1311 NULL, GNUNET_SYSERR \
1127 } 1312 }
1128 1313
1129 1314
1130/** 1315/**
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
107 107
108 108
109/** 109/**
110 * Internal types that are supported as array types.
111 */
112
113enum array_types
114{
115 array_of_bool,
116 array_of_uint16,
117 array_of_uint32,
118 array_of_uint64,
119 array_of_byte, /* buffers of (char *), (void *), ... */
120 array_of_string, /* NULL-terminated (char *) */
121 array_of_abs_time,
122 array_of_rel_time,
123 array_of_timestamp,
124 array_of_MAX, /* must be last */
125};
126
127/**
128 * the header for a postgresql array in binary format. note that this a
129 * simplified special case of the general structure (which contains pointers),
130 * as we only support one-dimensional arrays.
131 */
132struct pq_array_header
133{
134 uint32_t ndim; /* number of dimensions. we only support ndim = 1 */
135 uint32_t has_null;
136 uint32_t oid;
137 uint32_t dim; /* size of the array */
138 uint32_t lbound; /* index value of first element in the db (default: 1). */
139} __attribute__((packed));
140
141
142/**
110 * Internal API. Reconnect should re-register notifications 143 * Internal API. Reconnect should re-register notifications
111 * after a disconnect. 144 * after a disconnect.
112 * 145 *
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 (
576 576
577 577
578/** 578/**
579 * The header for a Postgresql array in binary format. Note that this a
580 * simplified special case of the general structure (which contains pointers),
581 * as we only support one-dimensional arrays.
582 */
583struct pq_array_header
584{
585 uint32_t ndim; /* Number of dimensions. We only support ndim = 1 */
586 uint32_t has_null;
587 uint32_t oid;
588 uint32_t dim; /* Size of the array */
589 uint32_t lbound; /* Index value of first element in the DB (default: 1). */
590} __attribute__((packed));
591
592/**
593 * Internal types that are supported as array types.
594 */
595
596enum array_types
597{
598 array_of_bool,
599 array_of_uint16,
600 array_of_uint32,
601 array_of_uint64,
602 array_of_byte, /* buffers of (char *), (void *), ... */
603 array_of_string, /* NULL-terminated (char *) */
604 array_of_abs_time,
605 array_of_rel_time,
606 array_of_timestamp,
607 array_of_MAX, /* must be last */
608};
609
610/**
611 * Closure for the array type handlers. 579 * Closure for the array type handlers.
612 * 580 *
613 * May contain sizes information for the data, given (and handled) by the 581 * May contain sizes information for the data, given (and handled) by the
@@ -631,8 +599,8 @@ struct qconv_array_cls
631 599
632 /** 600 /**
633 * If true, the array parameter to the data pointer to the qconv_array is a 601 * If true, the array parameter to the data pointer to the qconv_array is a
634 * continuous byte array of data, either with @a same_size each or sizes provided bytes 602 * continuous byte array of data, either with @a same_size each or sizes
635 * by @a sizes; 603 * provided bytes by @a sizes;
636 */ 604 */
637 bool continuous; 605 bool continuous;
638 606
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 @@
22 * @brief functions to extract result values 22 * @brief functions to extract result values
23 * @author Christian Grothoff 23 * @author Christian Grothoff
24 */ 24 */
25#include "gnunet_common.h"
26#include "gnunet_time_lib.h"
25#include "platform.h" 27#include "platform.h"
26#include "gnunet_util_lib.h" 28#include "gnunet_util_lib.h"
27#include "gnunet_pq_lib.h" 29#include "gnunet_pq_lib.h"
30#include "pq.h"
28 31
29 32
30struct GNUNET_PQ_ResultSpec 33struct GNUNET_PQ_ResultSpec
@@ -1117,4 +1120,530 @@ GNUNET_PQ_result_spec_uint64 (const char *name,
1117} 1120}
1118 1121
1119 1122
1123/**
1124 * Closure for the array result specifications. Contains type information
1125 * for the generic parser extract_array_generic and out-pointers for the results.
1126 */
1127struct array_result_cls
1128{
1129 /* Oid of the expected type, must match the oid in the header of the PQResult struct */
1130 Oid oid;
1131
1132 /* Target type */
1133 enum array_types typ;
1134
1135 /* If not 0, defines the expected size of each entry */
1136 size_t same_size;
1137
1138 /* Out-pointer to write the number of elements in the array */
1139 size_t *num;
1140
1141 /* Out-pointer. If @a typ is array_of_byte and @a same_size is 0,
1142 * allocate and put the array of @a num sizes here. NULL otherwise */
1143 size_t **sizes;
1144};
1145
1146
1147/**
1148 * Extract data from a Postgres database @a result as array of a specific type
1149 * from row @a row. The type information and optionally additional
1150 * out-parameters are given in @a cls which is of type array_result_cls.
1151 *
1152 * @param cls closure of type array_result_cls
1153 * @param result where to extract data from
1154 * @param row row to extract data from
1155 * @param fname name (or prefix) of the fields to extract from
1156 * @param[in,out] dst_size where to store size of result, may be NULL
1157 * @param[out] dst where to store the result
1158 * @return
1159 * #GNUNET_YES if all results could be extracted
1160 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
1161 */
1162static enum GNUNET_GenericReturnValue
1163extract_array_generic (
1164 void *cls,
1165 PGresult *result,
1166 int row,
1167 const char *fname,
1168 size_t *dst_size,
1169 void *dst)
1170{
1171 const struct array_result_cls *info = cls;
1172 int data_sz;
1173 char *data;
1174 void *out = NULL;
1175 struct pq_array_header header;
1176 int col_num;
1177
1178 GNUNET_assert (NULL != dst);
1179 *((void **) dst) = NULL;
1180
1181 #define FAIL_IF(cond) \
1182 do { \
1183 if ((cond)) \
1184 { \
1185 GNUNET_break (! (cond)); \
1186 goto FAIL; \
1187 } \
1188 } while(0)
1189
1190 col_num = PQfnumber (result, fname);
1191 FAIL_IF (0 > col_num);
1192
1193 data_sz = PQgetlength (result, row, col_num);
1194 FAIL_IF (0 > data_sz);
1195 FAIL_IF (sizeof(header) > (size_t) data_sz);
1196
1197 data = PQgetvalue (result, row, col_num);
1198 FAIL_IF (NULL == data);
1199
1200 {
1201 struct pq_array_header *h =
1202 (struct pq_array_header *) data;
1203
1204 header.ndim = ntohl (h->ndim);
1205 header.has_null = ntohl (h->has_null);
1206 header.oid = ntohl (h->oid);
1207 header.dim = ntohl (h->dim);
1208 header.lbound = ntohl (h->lbound);
1209
1210 FAIL_IF (1 != header.ndim);
1211 FAIL_IF ((0 > header.dim) || (INT_MAX == header.dim));
1212 FAIL_IF (0 != header.has_null);
1213 FAIL_IF (1 != header.lbound);
1214 FAIL_IF (info->oid != header.oid);
1215 }
1216
1217 *info->num = header.dim;
1218 switch (info->typ)
1219 {
1220 case array_of_bool:
1221 if (NULL != dst_size)
1222 *dst_size = sizeof(bool) * (*info->num);
1223 out = GNUNET_new_array (*info->num, bool);
1224 break;
1225 case array_of_uint16:
1226 if (NULL != dst_size)
1227 *dst_size = sizeof(uint16_t) * (*info->num);
1228 out = GNUNET_new_array (*info->num, uint16_t);
1229 break;
1230 case array_of_uint32:
1231 if (NULL != dst_size)
1232 *dst_size = sizeof(uint32_t) * (*info->num);
1233 out = GNUNET_new_array (*info->num, uint32_t);
1234 break;
1235 case array_of_uint64:
1236 if (NULL != dst_size)
1237 *dst_size = sizeof(uint64_t) * (*info->num);
1238 out = GNUNET_new_array (*info->num, uint64_t);
1239 break;
1240 case array_of_abs_time:
1241 if (NULL != dst_size)
1242 *dst_size = sizeof(struct GNUNET_TIME_Absolute) * (*info->num);
1243 out = GNUNET_new_array (*info->num, struct GNUNET_TIME_Absolute);
1244 break;
1245 case array_of_rel_time:
1246 if (NULL != dst_size)
1247 *dst_size = sizeof(struct GNUNET_TIME_Relative) * (*info->num);
1248 out = GNUNET_new_array (*info->num, struct GNUNET_TIME_Relative);
1249 break;
1250 case array_of_timestamp:
1251 if (NULL != dst_size)
1252 *dst_size = sizeof(struct GNUNET_TIME_Timestamp) * (*info->num);
1253 out = GNUNET_new_array (*info->num, struct GNUNET_TIME_Timestamp);
1254 break;
1255 case array_of_byte:
1256 if (0 == info->same_size)
1257 *info->sizes = GNUNET_new_array (header.dim, size_t);
1258 /* fallthrough */
1259 case array_of_string:
1260 {
1261 size_t total = 0;
1262 bool is_string = (array_of_string == info->typ);
1263
1264 /* first, calculate total size required for allocation */
1265 {
1266 char *ptr = data + sizeof(header);
1267 for (uint32_t i = 0; i < header.dim; i++)
1268 {
1269 uint32_t sz;
1270
1271 sz = ntohl (*(uint32_t *) ptr);
1272 sz += is_string ? 1 : 0;
1273 total += sz;
1274 ptr += sizeof(uint32_t);
1275 ptr += sz;
1276
1277 if ((! is_string) &&
1278 (0 == info->same_size))
1279 (*info->sizes)[i] = sz;
1280
1281 FAIL_IF ((0 != info->same_size) &&
1282 (sz != info->same_size));
1283 FAIL_IF (total < sz);
1284 }
1285 }
1286
1287 if (NULL != dst_size)
1288 *dst_size = total;
1289
1290 if (0 < total)
1291 out = GNUNET_malloc (total);
1292
1293 break;
1294 }
1295 default:
1296 FAIL_IF (1 != 0);
1297 }
1298
1299 *((void **) dst) = out;
1300
1301 /* copy data */
1302 {
1303 char *in = data + sizeof(header);
1304
1305 for (uint32_t i = 0; i < header.dim; i++)
1306 {
1307 size_t sz = ntohl (*(uint32_t *) in);
1308 in += sizeof(uint32_t);
1309
1310 switch (info->typ)
1311 {
1312 case array_of_bool:
1313 FAIL_IF (sz != sizeof(bool));
1314 *(bool *) out = *(bool *) in;
1315 break;
1316 case array_of_uint16:
1317 FAIL_IF (sz != sizeof(uint16_t));
1318 *(uint16_t *) out = ntohs (*(uint16_t *) in);
1319 break;
1320 case array_of_uint32:
1321 FAIL_IF (sz != sizeof(uint32_t));
1322 *(uint32_t *) out = ntohl (*(uint32_t *) in);
1323 break;
1324 case array_of_uint64:
1325 FAIL_IF (sz != sizeof(uint64_t));
1326 *(uint64_t *) out = GNUNET_ntohll (*(uint64_t *) in);
1327 break;
1328 case array_of_abs_time:
1329 case array_of_rel_time:
1330 case array_of_timestamp:
1331 FAIL_IF (sz != sizeof(uint64_t));
1332 {
1333 uint64_t val = GNUNET_ntohll (*(uint64_t *) in);
1334 switch (info->typ)
1335 {
1336 case array_of_abs_time:
1337 ((struct GNUNET_TIME_Absolute *) out)->abs_value_us = val;
1338 break;
1339 case array_of_rel_time:
1340 ((struct GNUNET_TIME_Relative *) out)->rel_value_us = val;
1341 break;
1342 case array_of_timestamp:
1343 ((struct GNUNET_TIME_Timestamp *) out)->abs_time.abs_value_us = val;
1344 break;
1345 default:
1346 FAIL_IF (1 != 0);
1347 }
1348 }
1349 break;
1350 case array_of_byte:
1351 case array_of_string:
1352 GNUNET_memcpy (out, in, sz);
1353 break;
1354 default:
1355 FAIL_IF (1 != 0);
1356 }
1357
1358 in += sz;
1359 out += sz;
1360 out += (array_of_string == info->typ) ? 1 : 0;
1361 }
1362 }
1363
1364 return GNUNET_OK;
1365
1366FAIL:
1367 GNUNET_free (*(void **) dst);
1368 return GNUNET_SYSERR;
1369 #undef FAIL_IF
1370}
1371
1372
1373/**
1374 * Cleanup of the data and closure of an array spec.
1375 */
1376static void
1377array_cleanup (void *cls,
1378 void *rd)
1379{
1380
1381 struct array_result_cls *info = cls;
1382 void **dst = rd;
1383
1384 if ((array_of_byte == info->typ) &&
1385 (0 == info->same_size) &&
1386 (NULL != info->sizes))
1387 GNUNET_free (*(info->sizes));
1388
1389 GNUNET_free (cls);
1390 GNUNET_free (*dst);
1391 *dst = NULL;
1392}
1393
1394
1395struct GNUNET_PQ_ResultSpec
1396GNUNET_PQ_result_spec_array_bool (
1397 const struct GNUNET_PQ_Context *db,
1398 const char *name,
1399 size_t *num,
1400 bool **dst)
1401{
1402 struct array_result_cls *info =
1403 GNUNET_new (struct array_result_cls);
1404
1405 info->num = num;
1406 info->typ = array_of_bool;
1407 info->oid = db->oids[GNUNET_PQ_DATATYPE_BOOL];
1408
1409 struct GNUNET_PQ_ResultSpec res = {
1410 .conv = extract_array_generic,
1411 .cleaner = array_cleanup,
1412 .dst = (void *) dst,
1413 .fname = name,
1414 .cls = info
1415 };
1416 return res;
1417}
1418
1419
1420struct GNUNET_PQ_ResultSpec
1421GNUNET_PQ_result_spec_array_uint16 (
1422 const struct GNUNET_PQ_Context *db,
1423 const char *name,
1424 size_t *num,
1425 uint16_t **dst)
1426{
1427 struct array_result_cls *info =
1428 GNUNET_new (struct array_result_cls);
1429
1430 info->num = num;
1431 info->typ = array_of_uint16;
1432 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT2];
1433
1434 struct GNUNET_PQ_ResultSpec res = {
1435 .conv = extract_array_generic,
1436 .cleaner = array_cleanup,
1437 .dst = (void *) dst,
1438 .fname = name,
1439 .cls = info
1440 };
1441 return res;
1442}
1443
1444
1445struct GNUNET_PQ_ResultSpec
1446GNUNET_PQ_result_spec_array_uint32 (
1447 const struct GNUNET_PQ_Context *db,
1448 const char *name,
1449 size_t *num,
1450 uint32_t **dst)
1451{
1452 struct array_result_cls *info =
1453 GNUNET_new (struct array_result_cls);
1454
1455 info->num = num;
1456 info->typ = array_of_uint32;
1457 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT4];
1458
1459 struct GNUNET_PQ_ResultSpec res = {
1460 .conv = extract_array_generic,
1461 .cleaner = array_cleanup,
1462 .dst = (void *) dst,
1463 .fname = name,
1464 .cls = info
1465 };
1466 return res;
1467}
1468
1469
1470struct GNUNET_PQ_ResultSpec
1471GNUNET_PQ_result_spec_array_uint64 (
1472 const struct GNUNET_PQ_Context *db,
1473 const char *name,
1474 size_t *num,
1475 uint64_t **dst)
1476{
1477 struct array_result_cls *info =
1478 GNUNET_new (struct array_result_cls);
1479
1480 info->num = num;
1481 info->typ = array_of_uint64;
1482 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
1483
1484 struct GNUNET_PQ_ResultSpec res = {
1485 .conv = extract_array_generic,
1486 .cleaner = array_cleanup,
1487 .dst = (void *) dst,
1488 .fname = name,
1489 .cls = info
1490 };
1491 return res;
1492}
1493
1494
1495struct GNUNET_PQ_ResultSpec
1496GNUNET_PQ_result_spec_array_abs_time (
1497 const struct GNUNET_PQ_Context *db,
1498 const char *name,
1499 size_t *num,
1500 struct GNUNET_TIME_Absolute **dst)
1501{
1502 struct array_result_cls *info =
1503 GNUNET_new (struct array_result_cls);
1504
1505 info->num = num;
1506 info->typ = array_of_abs_time;
1507 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
1508
1509 struct GNUNET_PQ_ResultSpec res = {
1510 .conv = extract_array_generic,
1511 .cleaner = array_cleanup,
1512 .dst = (void *) dst,
1513 .fname = name,
1514 .cls = info
1515 };
1516 return res;
1517}
1518
1519
1520struct GNUNET_PQ_ResultSpec
1521GNUNET_PQ_result_spec_array_rel_time (
1522 const struct GNUNET_PQ_Context *db,
1523 const char *name,
1524 size_t *num,
1525 struct GNUNET_TIME_Relative **dst)
1526{
1527 struct array_result_cls *info =
1528 GNUNET_new (struct array_result_cls);
1529
1530 info->num = num;
1531 info->typ = array_of_rel_time;
1532 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
1533
1534 struct GNUNET_PQ_ResultSpec res = {
1535 .conv = extract_array_generic,
1536 .cleaner = array_cleanup,
1537 .dst = (void *) dst,
1538 .fname = name,
1539 .cls = info
1540 };
1541 return res;
1542}
1543
1544
1545struct GNUNET_PQ_ResultSpec
1546GNUNET_PQ_result_spec_array_timestamp (
1547 const struct GNUNET_PQ_Context *db,
1548 const char *name,
1549 size_t *num,
1550 struct GNUNET_TIME_Timestamp **dst)
1551{
1552 struct array_result_cls *info =
1553 GNUNET_new (struct array_result_cls);
1554
1555 info->num = num;
1556 info->typ = array_of_timestamp;
1557 info->oid = db->oids[GNUNET_PQ_DATATYPE_INT8];
1558
1559 struct GNUNET_PQ_ResultSpec res = {
1560 .conv = extract_array_generic,
1561 .cleaner = array_cleanup,
1562 .dst = (void *) dst,
1563 .fname = name,
1564 .cls = info
1565 };
1566 return res;
1567}
1568
1569
1570struct GNUNET_PQ_ResultSpec
1571GNUNET_PQ_result_spec_array_variable_size (
1572 const struct GNUNET_PQ_Context *db,
1573 const char *name,
1574 size_t *num,
1575 size_t **sizes,
1576 void **dst)
1577{
1578 struct array_result_cls *info =
1579 GNUNET_new (struct array_result_cls);
1580
1581 info->num = num;
1582 info->sizes = sizes;
1583 info->typ = array_of_byte;
1584 info->oid = db->oids[GNUNET_PQ_DATATYPE_BYTEA];
1585
1586 struct GNUNET_PQ_ResultSpec res = {
1587 .conv = extract_array_generic,
1588 .cleaner = array_cleanup,
1589 .dst = (void *) dst,
1590 .fname = name,
1591 .cls = info
1592 };
1593 return res;
1594}
1595
1596
1597struct GNUNET_PQ_ResultSpec
1598GNUNET_PQ_result_spec_array_fixed_size (
1599 const struct GNUNET_PQ_Context *db,
1600 const char *name,
1601 size_t size,
1602 size_t *num,
1603 void **dst)
1604{
1605 struct array_result_cls *info =
1606 GNUNET_new (struct array_result_cls);
1607
1608 info->num = num;
1609 info->same_size = size;
1610 info->typ = array_of_byte;
1611 info->oid = db->oids[GNUNET_PQ_DATATYPE_BYTEA];
1612
1613 struct GNUNET_PQ_ResultSpec res = {
1614 .conv = extract_array_generic,
1615 .cleaner = array_cleanup,
1616 .dst = (void *) dst,
1617 .fname = name,
1618 .cls = info
1619 };
1620 return res;
1621}
1622
1623
1624struct GNUNET_PQ_ResultSpec
1625GNUNET_PQ_result_spec_array_string (
1626 const struct GNUNET_PQ_Context *db,
1627 const char *name,
1628 size_t *num,
1629 char **dst)
1630{
1631 struct array_result_cls *info =
1632 GNUNET_new (struct array_result_cls);
1633
1634 info->num = num;
1635 info->typ = array_of_string;
1636 info->oid = db->oids[GNUNET_PQ_DATATYPE_VARCHAR];
1637
1638 struct GNUNET_PQ_ResultSpec res = {
1639 .conv = extract_array_generic,
1640 .cleaner = array_cleanup,
1641 .dst = (void *) dst,
1642 .fname = name,
1643 .cls = info
1644 };
1645 return res;
1646}
1647
1648
1120/* end of pq_result_helper.c */ 1649/* 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 @@
23 * @author Christian Grothoff <christian@grothoff.org> 23 * @author Christian Grothoff <christian@grothoff.org>
24 */ 24 */
25#include "gnunet_common.h" 25#include "gnunet_common.h"
26#include "gnunet_pq_lib.h"
26#include "gnunet_time_lib.h" 27#include "gnunet_time_lib.h"
27#include "platform.h" 28#include "platform.h"
28#include "pq.h" 29#include "pq.h"
@@ -154,7 +155,7 @@ run_queries (struct GNUNET_PQ_Context *db)
154 uint16_t ai2[3] = {42, 0x0001, 0xFFFF}; 155 uint16_t ai2[3] = {42, 0x0001, 0xFFFF};
155 uint32_t ai4[3] = {42, 0x00010000, 0xFFFFFFFF}; 156 uint32_t ai4[3] = {42, 0x00010000, 0xFFFFFFFF};
156 uint64_t ai8[3] = {42, 0x0001000000000000, 0xFFFFFFFFFFFFFFFF}; 157 uint64_t ai8[3] = {42, 0x0001000000000000, 0xFFFFFFFFFFFFFFFF};
157 const char *as[] = {"foo", "bar", "buz"}; 158 const char *as[] = {"foo", "bar", "buzz"};
158 const struct GNUNET_TIME_Absolute ata[2] = {GNUNET_TIME_absolute_get (), 159 const struct GNUNET_TIME_Absolute ata[2] = {GNUNET_TIME_absolute_get (),
159 GNUNET_TIME_absolute_get ()}; 160 GNUNET_TIME_absolute_get ()};
160 const struct GNUNET_TIME_Relative atr[2] = {GNUNET_TIME_relative_get_hour_ (), 161 const struct GNUNET_TIME_Relative atr[2] = {GNUNET_TIME_relative_get_hour_ (),
@@ -208,6 +209,27 @@ run_queries (struct GNUNET_PQ_Context *db)
208 GNUNET_PQ_query_param_end 209 GNUNET_PQ_query_param_end
209 }; 210 };
210 bool got_null = false; 211 bool got_null = false;
212 size_t num_bool;
213 bool *arr_bools;
214 size_t num_u16;
215 uint16_t *arr_u16;
216 size_t num_u32;
217 uint32_t *arr_u32;
218 size_t num_u64;
219 uint64_t *arr_u64;
220 size_t num_abs;
221 struct GNUNET_TIME_Absolute *arr_abs;
222 size_t num_rel;
223 struct GNUNET_TIME_Relative *arr_rel;
224 size_t num_tstmp;
225 struct GNUNET_TIME_Timestamp *arr_tstmp;
226 size_t num_str;
227 char *arr_str;
228 size_t num_hash;
229 struct GNUNET_HashCode *arr_hash;
230 size_t num_buf;
231 void *arr_buf;
232 size_t *sz_buf;
211 struct GNUNET_PQ_ResultSpec results_select[] = { 233 struct GNUNET_PQ_ResultSpec results_select[] = {
212 GNUNET_PQ_result_spec_rsa_public_key ("pub", &pub2), 234 GNUNET_PQ_result_spec_rsa_public_key ("pub", &pub2),
213 GNUNET_PQ_result_spec_rsa_signature ("sig", &sig2), 235 GNUNET_PQ_result_spec_rsa_signature ("sig", &sig2),
@@ -221,6 +243,47 @@ run_queries (struct GNUNET_PQ_Context *db)
221 GNUNET_PQ_result_spec_allow_null ( 243 GNUNET_PQ_result_spec_allow_null (
222 GNUNET_PQ_result_spec_uint64 ("unn", &uzzz), 244 GNUNET_PQ_result_spec_uint64 ("unn", &uzzz),
223 &got_null), 245 &got_null),
246 GNUNET_PQ_result_spec_array_bool (db,
247 "arr_bool",
248 &num_bool,
249 &arr_bools),
250 GNUNET_PQ_result_spec_array_uint16 (db,
251 "arr_int2",
252 &num_u16,
253 &arr_u16),
254 GNUNET_PQ_result_spec_array_uint32 (db,
255 "arr_int4",
256 &num_u32,
257 &arr_u32),
258 GNUNET_PQ_result_spec_array_uint64 (db,
259 "arr_int8",
260 &num_u64,
261 &arr_u64),
262 GNUNET_PQ_result_spec_array_abs_time (db,
263 "arr_abs_time",
264 &num_abs,
265 &arr_abs),
266 GNUNET_PQ_result_spec_array_rel_time (db,
267 "arr_rel_time",
268 &num_rel,
269 &arr_rel),
270 GNUNET_PQ_result_spec_array_timestamp (db,
271 "arr_timestamp",
272 &num_tstmp,
273 &arr_tstmp),
274 GNUNET_PQ_result_spec_auto_array_from_type (db,
275 "arr_bytea",
276 &num_hash,
277 arr_hash),
278 GNUNET_PQ_result_spec_array_variable_size (db,
279 "arr_bytea",
280 &num_buf,
281 &sz_buf,
282 &arr_buf),
283 GNUNET_PQ_result_spec_array_string (db,
284 "arr_varchar",
285 &num_str,
286 &arr_str),
224 GNUNET_PQ_result_spec_end 287 GNUNET_PQ_result_spec_end
225 }; 288 };
226 289
@@ -278,6 +341,49 @@ run_queries (struct GNUNET_PQ_Context *db)
278 GNUNET_break (64 == u642); 341 GNUNET_break (64 == u642);
279 GNUNET_break (42 == uzzz); 342 GNUNET_break (42 == uzzz);
280 GNUNET_break (got_null); 343 GNUNET_break (got_null);
344
345 /* Check arrays */
346 {
347 GNUNET_break (num_bool == 5);
348 GNUNET_break (arr_bools[0]);
349 GNUNET_break (! arr_bools[1]);
350 GNUNET_break (! arr_bools[2]);
351 GNUNET_break (arr_bools[3]);
352 GNUNET_break (! arr_bools[4]);
353
354 GNUNET_break (num_u16 == 3);
355 GNUNET_break (arr_u16[0] == 42);
356 GNUNET_break (arr_u16[1] == 0x0001);
357 GNUNET_break (arr_u16[2] == 0xFFFF);
358
359 GNUNET_break (num_u32 == 3);
360 GNUNET_break (arr_u32[0] == 42);
361 GNUNET_break (arr_u32[1] == 0x00010000);
362 GNUNET_break (arr_u32[2] == 0xFFFFFFFF);
363
364 GNUNET_break (num_u64 == 3);
365 GNUNET_break (arr_u64[0] == 42);
366 GNUNET_break (arr_u64[1] == 0x0001000000000000);
367 GNUNET_break (arr_u64[2] == 0xFFFFFFFFFFFFFFFF);
368
369 GNUNET_break (num_str == 3);
370 GNUNET_break (0 == strcmp (arr_str, "foo"));
371 GNUNET_break (0 == strcmp (arr_str + 4, "bar"));
372 GNUNET_break (0 == strcmp (arr_str + 8, "buzz"));
373
374 GNUNET_break (num_hash == 3);
375 GNUNET_break (0 == GNUNET_memcmp (&arr_hash[0], &arr_hash[1]));
376 GNUNET_break (0 == GNUNET_memcmp (&arr_hash[1], &arr_hash[2]));
377
378 GNUNET_break (num_buf == 3);
379 {
380 char *ptr = arr_buf;
381 GNUNET_break (0 == memcmp (ptr, &ptr[sz_buf[0]], sz_buf[0]));
382 ptr += sz_buf[0];
383 GNUNET_break (0 == memcmp (ptr, &ptr[sz_buf[1]], sz_buf[1]));
384 }
385 }
386
281 GNUNET_PQ_cleanup_result (results_select); 387 GNUNET_PQ_cleanup_result (results_select);
282 PQclear (result); 388 PQclear (result);
283 389