diff options
author | Özgür Kesim <oec-taler@kesim.org> | 2023-06-02 16:14:32 +0200 |
---|---|---|
committer | Özgür Kesim <oec-taler@kesim.org> | 2023-06-02 16:14:32 +0200 |
commit | 5bf8a16e6a1aae1a59062a3ae3d8c939da0643ab (patch) | |
tree | 563c675c3c7f287fb460d56c394c2deb81af8331 | |
parent | 5ebd19e60b820bb96b4451c366c2f152ab30ff67 (diff) | |
download | gnunet-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.h | 253 | ||||
-rw-r--r-- | src/pq/pq.h | 33 | ||||
-rw-r--r-- | src/pq/pq_query_helper.c | 36 | ||||
-rw-r--r-- | src/pq/pq_result_helper.c | 529 | ||||
-rw-r--r-- | src/pq/test_pq.c | 108 |
5 files changed, 890 insertions, 69 deletions
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h index b21c6974f..78eaf0d49 100644 --- a/src/include/gnunet_pq_lib.h +++ b/src/include/gnunet_pq_lib.h | |||
@@ -131,13 +131,13 @@ GNUNET_PQ_cleanup_query_params_closures ( | |||
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 | |||
876 | GNUNET_PQ_result_spec_uint64 (const char *name, | 876 | GNUNET_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 | */ | ||
888 | struct GNUNET_PQ_ResultSpec | ||
889 | GNUNET_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 | */ | ||
904 | struct GNUNET_PQ_ResultSpec | ||
905 | GNUNET_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 | */ | ||
920 | struct GNUNET_PQ_ResultSpec | ||
921 | GNUNET_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 | */ | ||
936 | struct GNUNET_PQ_ResultSpec | ||
937 | GNUNET_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 | */ | ||
953 | struct GNUNET_PQ_ResultSpec | ||
954 | GNUNET_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 | */ | ||
969 | struct GNUNET_PQ_ResultSpec | ||
970 | GNUNET_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 | |||
986 | struct GNUNET_PQ_ResultSpec | ||
987 | GNUNET_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 | */ | ||
1003 | struct GNUNET_PQ_ResultSpec | ||
1004 | GNUNET_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 | */ | ||
1022 | struct GNUNET_PQ_ResultSpec | ||
1023 | GNUNET_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 | */ | ||
1058 | struct GNUNET_PQ_ResultSpec | ||
1059 | GNUNET_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 | |||
113 | enum 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 | */ | ||
132 | struct 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 | */ | ||
583 | struct 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 | |||
596 | enum 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 | ||
30 | struct GNUNET_PQ_ResultSpec | 33 | struct 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 | */ | ||
1127 | struct 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 | */ | ||
1162 | static enum GNUNET_GenericReturnValue | ||
1163 | extract_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 | |||
1366 | FAIL: | ||
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 | */ | ||
1376 | static void | ||
1377 | array_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 | |||
1395 | struct GNUNET_PQ_ResultSpec | ||
1396 | GNUNET_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 | |||
1420 | struct GNUNET_PQ_ResultSpec | ||
1421 | GNUNET_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 | |||
1445 | struct GNUNET_PQ_ResultSpec | ||
1446 | GNUNET_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 | |||
1470 | struct GNUNET_PQ_ResultSpec | ||
1471 | GNUNET_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 | |||
1495 | struct GNUNET_PQ_ResultSpec | ||
1496 | GNUNET_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 | |||
1520 | struct GNUNET_PQ_ResultSpec | ||
1521 | GNUNET_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 | |||
1545 | struct GNUNET_PQ_ResultSpec | ||
1546 | GNUNET_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 | |||
1570 | struct GNUNET_PQ_ResultSpec | ||
1571 | GNUNET_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 | |||
1597 | struct GNUNET_PQ_ResultSpec | ||
1598 | GNUNET_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 | |||
1624 | struct GNUNET_PQ_ResultSpec | ||
1625 | GNUNET_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 | ||