aboutsummaryrefslogtreecommitdiff
path: root/src/lib/pq/pq_result_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/pq/pq_result_helper.c')
-rw-r--r--src/lib/pq/pq_result_helper.c1714
1 files changed, 1714 insertions, 0 deletions
diff --git a/src/lib/pq/pq_result_helper.c b/src/lib/pq/pq_result_helper.c
new file mode 100644
index 000000000..f230826cb
--- /dev/null
+++ b/src/lib/pq/pq_result_helper.c
@@ -0,0 +1,1714 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014, 2015, 2016, 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file pq/pq_result_helper.c
22 * @brief functions to extract result values
23 * @author Christian Grothoff
24 * @author Özgür Kesim
25 */
26#include "platform.h"
27#include "gnunet_time_lib.h"
28#include "gnunet_common.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_pq_lib.h"
31#include "pq.h"
32
33
34struct GNUNET_PQ_ResultSpec
35GNUNET_PQ_result_spec_allow_null (struct GNUNET_PQ_ResultSpec rs,
36 bool *is_null)
37{
38 struct GNUNET_PQ_ResultSpec rsr;
39
40 rsr = rs;
41 rsr.is_nullable = true;
42 rsr.is_null = is_null;
43 return rsr;
44}
45
46
47/**
48 * Function called to clean up memory allocated
49 * by a #GNUNET_PQ_ResultConverter.
50 *
51 * @param cls closure
52 * @param rd result data to clean up
53 */
54static void
55clean_varsize_blob (void *cls,
56 void *rd)
57{
58 void **dst = rd;
59
60 (void) cls;
61 if (NULL != *dst)
62 {
63 GNUNET_free (*dst);
64 *dst = NULL;
65 }
66}
67
68
69/**
70 * Extract data from a Postgres database @a result at row @a row.
71 *
72 * @param cls closure
73 * @param result where to extract data from
74 * @param row row to extract data from
75 * @param fname name (or prefix) of the fields to extract from
76 * @param[in,out] dst_size where to store size of result, may be NULL
77 * @param[out] dst where to store the result
78 * @return
79 * #GNUNET_YES if all results could be extracted
80 * #GNUNET_SYSERR if a result was invalid (non-existing field)
81 */
82static enum GNUNET_GenericReturnValue
83extract_varsize_blob (void *cls,
84 PGresult *result,
85 int row,
86 const char *fname,
87 size_t *dst_size,
88 void *dst)
89{
90 size_t len;
91 const char *res;
92 void *idst;
93 int fnum;
94
95 (void) cls;
96 *dst_size = 0;
97 *((void **) dst) = NULL;
98
99 fnum = PQfnumber (result,
100 fname);
101 if (fnum < 0)
102 {
103 GNUNET_break (0);
104 return GNUNET_SYSERR;
105 }
106 if (PQgetisnull (result,
107 row,
108 fnum))
109 return GNUNET_NO;
110 /* if a field is null, continue but
111 * remember that we now return a different result */
112 len = PQgetlength (result,
113 row,
114 fnum);
115 res = PQgetvalue (result,
116 row,
117 fnum);
118 GNUNET_assert (NULL != res);
119 *dst_size = len;
120 idst = GNUNET_malloc (len);
121 *((void **) dst) = idst;
122 GNUNET_memcpy (idst,
123 res,
124 len);
125 return GNUNET_OK;
126}
127
128
129struct GNUNET_PQ_ResultSpec
130GNUNET_PQ_result_spec_variable_size (const char *name,
131 void **dst,
132 size_t *sptr)
133{
134 struct GNUNET_PQ_ResultSpec res = {
135 .conv = &extract_varsize_blob,
136 .cleaner = &clean_varsize_blob,
137 .dst = (void *) (dst),
138 .fname = name,
139 .result_size = sptr
140 };
141
142 return res;
143}
144
145
146/**
147 * Extract data from a Postgres database @a result at row @a row.
148 *
149 * @param cls closure
150 * @param result where to extract data from
151 * @param row row to extract data from
152 * @param fname name (or prefix) of the fields to extract from
153 * @param[in] dst_size desired size, never NULL
154 * @param[out] dst where to store the result
155 * @return
156 * #GNUNET_YES if all results could be extracted
157 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
158 */
159static enum GNUNET_GenericReturnValue
160extract_fixed_blob (void *cls,
161 PGresult *result,
162 int row,
163 const char *fname,
164 size_t *dst_size,
165 void *dst)
166{
167 size_t len;
168 const char *res;
169 int fnum;
170
171 (void) cls;
172 fnum = PQfnumber (result,
173 fname);
174 if (fnum < 0)
175 {
176 GNUNET_break (0);
177 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
178 "Result does not have field %s\n",
179 fname);
180 return GNUNET_SYSERR;
181 }
182 if (PQgetisnull (result,
183 row,
184 fnum))
185 return GNUNET_NO;
186 /* if a field is null, continue but
187 * remember that we now return a different result */
188 len = PQgetlength (result,
189 row,
190 fnum);
191 if (*dst_size != len)
192 {
193 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
194 "Expected %u bytes for field `%s', got %u\n",
195 (unsigned int) *dst_size,
196 fname,
197 (unsigned int) len);
198 GNUNET_break (0);
199 return GNUNET_SYSERR;
200 }
201 res = PQgetvalue (result,
202 row,
203 fnum);
204 GNUNET_assert (NULL != res);
205 GNUNET_memcpy (dst,
206 res,
207 len);
208 return GNUNET_OK;
209}
210
211
212struct GNUNET_PQ_ResultSpec
213GNUNET_PQ_result_spec_fixed_size (const char *name,
214 void *dst,
215 size_t dst_size)
216{
217 struct GNUNET_PQ_ResultSpec res = {
218 .conv = &extract_fixed_blob,
219 .dst = (dst),
220 .dst_size = dst_size,
221 .fname = name
222 };
223
224 return res;
225}
226
227
228/**
229 * Extract data from a Postgres database @a result at row @a row.
230 *
231 * @param cls closure
232 * @param result where to extract data from
233 * @param row row to extract data from
234 * @param fname name (or prefix) of the fields to extract from
235 * @param[in,out] dst_size where to store size of result, may be NULL
236 * @param[out] dst where to store the result
237 * @return
238 * #GNUNET_YES if all results could be extracted
239 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
240 */
241static enum GNUNET_GenericReturnValue
242extract_rsa_public_key (void *cls,
243 PGresult *result,
244 int row,
245 const char *fname,
246 size_t *dst_size,
247 void *dst)
248{
249 struct GNUNET_CRYPTO_RsaPublicKey **pk = dst;
250 size_t len;
251 const char *res;
252 int fnum;
253
254 (void) cls;
255 *pk = NULL;
256 fnum = PQfnumber (result,
257 fname);
258 if (fnum < 0)
259 {
260 GNUNET_break (0);
261 return GNUNET_SYSERR;
262 }
263 if (PQgetisnull (result,
264 row,
265 fnum))
266 return GNUNET_NO;
267
268 /* if a field is null, continue but
269 * remember that we now return a different result */
270 len = PQgetlength (result,
271 row,
272 fnum);
273 res = PQgetvalue (result,
274 row,
275 fnum);
276 *pk = GNUNET_CRYPTO_rsa_public_key_decode (res,
277 len);
278 if (NULL == *pk)
279 {
280 GNUNET_break (0);
281 return GNUNET_SYSERR;
282 }
283 return GNUNET_OK;
284}
285
286
287/**
288 * Function called to clean up memory allocated
289 * by a #GNUNET_PQ_ResultConverter.
290 *
291 * @param cls closure
292 * @param rd result data to clean up
293 */
294static void
295clean_rsa_public_key (void *cls,
296 void *rd)
297{
298 struct GNUNET_CRYPTO_RsaPublicKey **pk = rd;
299
300 (void) cls;
301 if (NULL != *pk)
302 {
303 GNUNET_CRYPTO_rsa_public_key_free (*pk);
304 *pk = NULL;
305 }
306}
307
308
309struct GNUNET_PQ_ResultSpec
310GNUNET_PQ_result_spec_rsa_public_key (const char *name,
311 struct GNUNET_CRYPTO_RsaPublicKey **rsa)
312{
313 struct GNUNET_PQ_ResultSpec res = {
314 .conv = &extract_rsa_public_key,
315 .cleaner = &clean_rsa_public_key,
316 .dst = (void *) rsa,
317 .fname = name
318 };
319
320 return res;
321}
322
323
324/**
325 * Extract data from a Postgres database @a result at row @a row.
326 *
327 * @param cls closure
328 * @param result where to extract data from
329 * @param row row to extract data from
330 * @param fname name (or prefix) of the fields to extract from
331 * @param[in,out] dst_size where to store size of result, may be NULL
332 * @param[out] dst where to store the result
333 * @return
334 * #GNUNET_YES if all results could be extracted
335 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
336 */
337static enum GNUNET_GenericReturnValue
338extract_rsa_signature (void *cls,
339 PGresult *result,
340 int row,
341 const char *fname,
342 size_t *dst_size,
343 void *dst)
344{
345 struct GNUNET_CRYPTO_RsaSignature **sig = dst;
346 size_t len;
347 const void *res;
348 int fnum;
349
350 (void) cls;
351 *sig = NULL;
352 fnum = PQfnumber (result,
353 fname);
354 if (fnum < 0)
355 {
356 GNUNET_break (0);
357 return GNUNET_SYSERR;
358 }
359 if (PQgetisnull (result,
360 row,
361 fnum))
362 return GNUNET_NO;
363 /* if a field is null, continue but
364 * remember that we now return a different result */
365 len = PQgetlength (result,
366 row,
367 fnum);
368 res = PQgetvalue (result,
369 row,
370 fnum);
371 *sig = GNUNET_CRYPTO_rsa_signature_decode (res,
372 len);
373 if (NULL == *sig)
374 {
375 GNUNET_break (0);
376 return GNUNET_SYSERR;
377 }
378 return GNUNET_OK;
379}
380
381
382/**
383 * Function called to clean up memory allocated
384 * by a #GNUNET_PQ_ResultConverter.
385 *
386 * @param cls closure
387 * @param rd result data to clean up
388 */
389static void
390clean_rsa_signature (void *cls,
391 void *rd)
392{
393 struct GNUNET_CRYPTO_RsaSignature **sig = rd;
394
395 (void) cls;
396 if (NULL != *sig)
397 {
398 GNUNET_CRYPTO_rsa_signature_free (*sig);
399 *sig = NULL;
400 }
401}
402
403
404struct GNUNET_PQ_ResultSpec
405GNUNET_PQ_result_spec_rsa_signature (const char *name,
406 struct GNUNET_CRYPTO_RsaSignature **sig)
407{
408 struct GNUNET_PQ_ResultSpec res = {
409 .conv = &extract_rsa_signature,
410 .cleaner = &clean_rsa_signature,
411 .dst = (void *) sig,
412 .fname = name
413 };
414
415 return res;
416}
417
418
419/**
420 * Extract data from a Postgres database @a result at row @a row.
421 *
422 * @param cls closure
423 * @param result where to extract data from
424 * @param row row to extract data from
425 * @param fname name (or prefix) of the fields to extract from
426 * @param[in,out] dst_size where to store size of result, may be NULL
427 * @param[out] dst where to store the result
428 * @return
429 * #GNUNET_YES if all results could be extracted
430 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
431 */
432static enum GNUNET_GenericReturnValue
433extract_string (void *cls,
434 PGresult *result,
435 int row,
436 const char *fname,
437 size_t *dst_size,
438 void *dst)
439{
440 char **str = dst;
441 size_t len;
442 const char *res;
443 int fnum;
444
445 (void) cls;
446 *str = NULL;
447 fnum = PQfnumber (result,
448 fname);
449 if (fnum < 0)
450 {
451 GNUNET_break (0);
452 return GNUNET_SYSERR;
453 }
454 if (PQgetisnull (result,
455 row,
456 fnum))
457 return GNUNET_NO;
458 /* if a field is null, continue but
459 * remember that we now return a different result */
460 len = PQgetlength (result,
461 row,
462 fnum);
463 res = PQgetvalue (result,
464 row,
465 fnum);
466 *str = GNUNET_strndup (res,
467 len);
468 if (NULL == *str)
469 {
470 GNUNET_break (0);
471 return GNUNET_SYSERR;
472 }
473 return GNUNET_OK;
474}
475
476
477/**
478 * Function called to clean up memory allocated
479 * by a #GNUNET_PQ_ResultConverter.
480 *
481 * @param cls closure
482 * @param rd result data to clean up
483 */
484static void
485clean_string (void *cls,
486 void *rd)
487{
488 char **str = rd;
489
490 (void) cls;
491 if (NULL != *str)
492 {
493 GNUNET_free (*str);
494 *str = NULL;
495 }
496}
497
498
499struct GNUNET_PQ_ResultSpec
500GNUNET_PQ_result_spec_string (const char *name,
501 char **dst)
502{
503 struct GNUNET_PQ_ResultSpec res = {
504 .conv = &extract_string,
505 .cleaner = &clean_string,
506 .dst = (void *) dst,
507 .fname = (name)
508 };
509
510 return res;
511}
512
513
514/**
515 * Extract data from a Postgres database @a result at row @a row.
516 *
517 * @param cls closure
518 * @param result where to extract data from
519 * @param row row to extract data from
520 * @param fname name (or prefix) of the fields to extract from
521 * @param[in,out] dst_size where to store size of result, may be NULL
522 * @param[out] dst where to store the result
523 * @return
524 * #GNUNET_YES if all results could be extracted
525 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
526 */
527static enum GNUNET_GenericReturnValue
528extract_bool (void *cls,
529 PGresult *result,
530 int row,
531 const char *fname,
532 size_t *dst_size,
533 void *dst)
534{
535 bool *b = dst;
536 const uint8_t *res;
537 int fnum;
538 size_t len;
539
540 (void) cls;
541 fnum = PQfnumber (result,
542 fname);
543 if (fnum < 0)
544 {
545 GNUNET_break (0);
546 return GNUNET_SYSERR;
547 }
548 if (PQgetisnull (result,
549 row,
550 fnum))
551 return GNUNET_NO;
552 /* if a field is null, continue but
553 * remember that we now return a different result */
554 len = PQgetlength (result,
555 row,
556 fnum);
557 if (sizeof (uint8_t) != len)
558 {
559 GNUNET_break (0);
560 return GNUNET_SYSERR;
561 }
562 res = (const uint8_t *) PQgetvalue (result,
563 row,
564 fnum);
565 *b = (0 != *res);
566 return GNUNET_OK;
567}
568
569
570struct GNUNET_PQ_ResultSpec
571GNUNET_PQ_result_spec_bool (const char *name,
572 bool *dst)
573{
574 struct GNUNET_PQ_ResultSpec res = {
575 .conv = &extract_bool,
576 .dst = (void *) dst,
577 .fname = name
578 };
579
580 return res;
581}
582
583
584/**
585 * Extract data from a Postgres database @a result at row @a row.
586 *
587 * @param cls closure
588 * @param result where to extract data from
589 * @param row row to extract data from
590 * @param fname name (or prefix) of the fields to extract from
591 * @param[in,out] dst_size where to store size of result, may be NULL
592 * @param[out] dst where to store the result
593 * @return
594 * #GNUNET_YES if all results could be extracted
595 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
596 */
597static enum GNUNET_GenericReturnValue
598extract_rel_time (void *cls,
599 PGresult *result,
600 int row,
601 const char *fname,
602 size_t *dst_size,
603 void *dst)
604{
605 struct GNUNET_TIME_Relative *udst = dst;
606 const int64_t *res;
607 int fnum;
608
609 (void) cls;
610 fnum = PQfnumber (result,
611 fname);
612 if (fnum < 0)
613 {
614 GNUNET_break (0);
615 return GNUNET_SYSERR;
616 }
617 if (PQgetisnull (result,
618 row,
619 fnum))
620 return GNUNET_NO;
621 GNUNET_assert (NULL != dst);
622 if (sizeof(struct GNUNET_TIME_Relative) != *dst_size)
623 {
624 GNUNET_break (0);
625 return GNUNET_SYSERR;
626 }
627 if (sizeof(int64_t) !=
628 PQgetlength (result,
629 row,
630 fnum))
631 {
632 GNUNET_break (0);
633 return GNUNET_SYSERR;
634 }
635 res = (int64_t *) PQgetvalue (result,
636 row,
637 fnum);
638 if (INT64_MAX == GNUNET_ntohll ((uint64_t) *res))
639 *udst = GNUNET_TIME_UNIT_FOREVER_REL;
640 else
641 udst->rel_value_us = GNUNET_ntohll ((uint64_t) *res);
642 return GNUNET_OK;
643}
644
645
646struct GNUNET_PQ_ResultSpec
647GNUNET_PQ_result_spec_relative_time (const char *name,
648 struct GNUNET_TIME_Relative *rt)
649{
650 struct GNUNET_PQ_ResultSpec res = {
651 .conv = &extract_rel_time,
652 .dst = (void *) rt,
653 .dst_size = sizeof(*rt),
654 .fname = name
655 };
656
657 return res;
658}
659
660
661/**
662 * Extract data from a Postgres database @a result at row @a row.
663 *
664 * @param cls closure
665 * @param result where to extract data from
666 * @param row row to extract data from
667 * @param fname name (or prefix) of the fields to extract from
668 * @param[in,out] dst_size where to store size of result, may be NULL
669 * @param[out] dst where to store the result
670 * @return
671 * #GNUNET_YES if all results could be extracted
672 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
673 */
674static enum GNUNET_GenericReturnValue
675extract_abs_time (void *cls,
676 PGresult *result,
677 int row,
678 const char *fname,
679 size_t *dst_size,
680 void *dst)
681{
682 struct GNUNET_TIME_Absolute *udst = dst;
683 const int64_t *res;
684 int fnum;
685
686 (void) cls;
687 fnum = PQfnumber (result,
688 fname);
689 if (fnum < 0)
690 {
691 GNUNET_break (0);
692 return GNUNET_SYSERR;
693 }
694 if (PQgetisnull (result,
695 row,
696 fnum))
697 return GNUNET_NO;
698 GNUNET_assert (NULL != dst);
699 if (sizeof(struct GNUNET_TIME_Absolute) != *dst_size)
700 {
701 GNUNET_break (0);
702 return GNUNET_SYSERR;
703 }
704 if (sizeof(int64_t) !=
705 PQgetlength (result,
706 row,
707 fnum))
708 {
709 GNUNET_break (0);
710 return GNUNET_SYSERR;
711 }
712 res = (int64_t *) PQgetvalue (result,
713 row,
714 fnum);
715 if (INT64_MAX == GNUNET_ntohll ((uint64_t) *res))
716 *udst = GNUNET_TIME_UNIT_FOREVER_ABS;
717 else
718 udst->abs_value_us = GNUNET_ntohll ((uint64_t) *res);
719 return GNUNET_OK;
720}
721
722
723struct GNUNET_PQ_ResultSpec
724GNUNET_PQ_result_spec_absolute_time (const char *name,
725 struct GNUNET_TIME_Absolute *at)
726{
727 struct GNUNET_PQ_ResultSpec res = {
728 .conv = &extract_abs_time,
729 .dst = (void *) at,
730 .dst_size = sizeof(*at),
731 .fname = name
732 };
733
734 return res;
735}
736
737
738struct GNUNET_PQ_ResultSpec
739GNUNET_PQ_result_spec_absolute_time_nbo (const char *name,
740 struct GNUNET_TIME_AbsoluteNBO *at)
741{
742 struct GNUNET_PQ_ResultSpec res =
743 GNUNET_PQ_result_spec_auto_from_type (name,
744 &at->abs_value_us__);
745
746 return res;
747}
748
749
750/**
751 * Extract data from a Postgres database @a result at row @a row.
752 *
753 * @param cls closure
754 * @param result where to extract data from
755 * @param row row to extract data from
756 * @param fname name (or prefix) of the fields to extract from
757 * @param[in,out] dst_size where to store size of result, may be NULL
758 * @param[out] dst where to store the result
759 * @return
760 * #GNUNET_YES if all results could be extracted
761 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
762 */
763static enum GNUNET_GenericReturnValue
764extract_timestamp (void *cls,
765 PGresult *result,
766 int row,
767 const char *fname,
768 size_t *dst_size,
769 void *dst)
770{
771 struct GNUNET_TIME_Timestamp *udst = dst;
772 struct GNUNET_TIME_Absolute abs;
773 const int64_t *res;
774 int fnum;
775
776 (void) cls;
777 fnum = PQfnumber (result,
778 fname);
779 if (fnum < 0)
780 {
781 GNUNET_break (0);
782 return GNUNET_SYSERR;
783 }
784 if (PQgetisnull (result,
785 row,
786 fnum))
787 return GNUNET_NO;
788 GNUNET_assert (NULL != dst);
789 if (sizeof(struct GNUNET_TIME_Absolute) != *dst_size)
790 {
791 GNUNET_break (0);
792 return GNUNET_SYSERR;
793 }
794 if (sizeof(int64_t) !=
795 PQgetlength (result,
796 row,
797 fnum))
798 {
799 GNUNET_break (0);
800 return GNUNET_SYSERR;
801 }
802 res = (int64_t *) PQgetvalue (result,
803 row,
804 fnum);
805 if (INT64_MAX == GNUNET_ntohll ((uint64_t) *res))
806 {
807 abs = GNUNET_TIME_UNIT_FOREVER_ABS;
808 }
809 else
810 {
811 abs.abs_value_us = GNUNET_ntohll ((uint64_t) *res);
812 if (0 != abs.abs_value_us % GNUNET_TIME_UNIT_SECONDS.rel_value_us)
813 {
814 /* timestamps must be multiple of seconds! */
815 GNUNET_break (0);
816 return GNUNET_SYSERR;
817 }
818 }
819 udst->abs_time = abs;
820 return GNUNET_OK;
821}
822
823
824struct GNUNET_PQ_ResultSpec
825GNUNET_PQ_result_spec_timestamp (const char *name,
826 struct GNUNET_TIME_Timestamp *at)
827{
828 struct GNUNET_PQ_ResultSpec res = {
829 .conv = &extract_timestamp,
830 .dst = (void *) at,
831 .dst_size = sizeof(*at),
832 .fname = name
833 };
834
835 return res;
836}
837
838
839/**
840 * Extract data from a Postgres database @a result at row @a row.
841 *
842 * @param cls closure
843 * @param result where to extract data from
844 * @param row row to extract data from
845 * @param fname name (or prefix) of the fields to extract from
846 * @param[in,out] dst_size where to store size of result, may be NULL
847 * @param[out] dst where to store the result
848 * @return
849 * #GNUNET_YES if all results could be extracted
850 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
851 */
852static enum GNUNET_GenericReturnValue
853extract_timestamp_nbo (void *cls,
854 PGresult *result,
855 int row,
856 const char *fname,
857 size_t *dst_size,
858 void *dst)
859{
860 struct GNUNET_TIME_TimestampNBO *udst = dst;
861 struct GNUNET_TIME_Timestamp t;
862 enum GNUNET_GenericReturnValue r;
863
864 r = extract_timestamp (NULL,
865 result,
866 row,
867 fname,
868 dst_size,
869 &t);
870 if (GNUNET_OK != r)
871 return r;
872 *udst = GNUNET_TIME_timestamp_hton (t);
873 return r;
874}
875
876
877struct GNUNET_PQ_ResultSpec
878GNUNET_PQ_result_spec_timestamp_nbo (const char *name,
879 struct GNUNET_TIME_TimestampNBO *at)
880{
881 struct GNUNET_PQ_ResultSpec res = {
882 .conv = &extract_timestamp_nbo,
883 .dst = (void *) at,
884 .dst_size = sizeof(*at),
885 .fname = name
886 };
887
888 return res;
889}
890
891
892/**
893 * Extract data from a Postgres database @a result at row @a row.
894 *
895 * @param cls closure
896 * @param result where to extract data from
897 * @param row row to extract data from
898 * @param fname name (or prefix) of the fields to extract from
899 * @param[in,out] dst_size where to store size of result, may be NULL
900 * @param[out] dst where to store the result
901 * @return
902 * #GNUNET_YES if all results could be extracted
903 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
904 */
905static enum GNUNET_GenericReturnValue
906extract_uint16 (void *cls,
907 PGresult *result,
908 int row,
909 const char *fname,
910 size_t *dst_size,
911 void *dst)
912{
913 uint16_t *udst = dst;
914 const uint16_t *res;
915 int fnum;
916
917 (void) cls;
918 fnum = PQfnumber (result,
919 fname);
920 if (fnum < 0)
921 {
922 GNUNET_break (0);
923 return GNUNET_SYSERR;
924 }
925 if (PQgetisnull (result,
926 row,
927 fnum))
928 return GNUNET_NO;
929 GNUNET_assert (NULL != dst);
930 if (sizeof(uint16_t) != *dst_size)
931 {
932 GNUNET_break (0);
933 return GNUNET_SYSERR;
934 }
935 if (sizeof(uint16_t) !=
936 PQgetlength (result,
937 row,
938 fnum))
939 {
940 GNUNET_break (0);
941 return GNUNET_SYSERR;
942 }
943 res = (uint16_t *) PQgetvalue (result,
944 row,
945 fnum);
946 *udst = ntohs (*res);
947 return GNUNET_OK;
948}
949
950
951struct GNUNET_PQ_ResultSpec
952GNUNET_PQ_result_spec_uint16 (const char *name,
953 uint16_t *u16)
954{
955 struct GNUNET_PQ_ResultSpec res = {
956 .conv = &extract_uint16,
957 .dst = (void *) u16,
958 .dst_size = sizeof(*u16),
959 .fname = name
960 };
961
962 return res;
963}
964
965
966/**
967 * Extract data from a Postgres database @a result at row @a row.
968 *
969 * @param cls closure
970 * @param result where to extract data from
971 * @param row row to extract data from
972 * @param fname name (or prefix) of the fields to extract from
973 * @param[in,out] dst_size where to store size of result, may be NULL
974 * @param[out] dst where to store the result
975 * @return
976 * #GNUNET_YES if all results could be extracted
977 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
978 */
979static enum GNUNET_GenericReturnValue
980extract_uint32 (void *cls,
981 PGresult *result,
982 int row,
983 const char *fname,
984 size_t *dst_size,
985 void *dst)
986{
987 uint32_t *udst = dst;
988 const uint32_t *res;
989 int fnum;
990
991 (void) cls;
992 fnum = PQfnumber (result,
993 fname);
994 if (fnum < 0)
995 {
996 GNUNET_break (0);
997 return GNUNET_SYSERR;
998 }
999 if (PQgetisnull (result,
1000 row,
1001 fnum))
1002 return GNUNET_NO;
1003 GNUNET_assert (NULL != dst);
1004 if (sizeof(uint32_t) != *dst_size)
1005 {
1006 GNUNET_break (0);
1007 return GNUNET_SYSERR;
1008 }
1009 if (sizeof(uint32_t) !=
1010 PQgetlength (result,
1011 row,
1012 fnum))
1013 {
1014 GNUNET_break (0);
1015 return GNUNET_SYSERR;
1016 }
1017 res = (uint32_t *) PQgetvalue (result,
1018 row,
1019 fnum);
1020 *udst = ntohl (*res);
1021 return GNUNET_OK;
1022}
1023
1024
1025struct GNUNET_PQ_ResultSpec
1026GNUNET_PQ_result_spec_uint32 (const char *name,
1027 uint32_t *u32)
1028{
1029 struct GNUNET_PQ_ResultSpec res = {
1030 .conv = &extract_uint32,
1031 .dst = (void *) u32,
1032 .dst_size = sizeof(*u32),
1033 .fname = name
1034 };
1035
1036 return res;
1037}
1038
1039
1040/**
1041 * Extract data from a Postgres database @a result at row @a row.
1042 *
1043 * @param cls closure
1044 * @param result where to extract data from
1045 * @param row row to extract data from
1046 * @param fname name (or prefix) of the fields to extract from
1047 * @param[in,out] dst_size where to store size of result, may be NULL
1048 * @param[out] dst where to store the result
1049 * @return
1050 * #GNUNET_YES if all results could be extracted
1051 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
1052 */
1053static enum GNUNET_GenericReturnValue
1054extract_uint64 (void *cls,
1055 PGresult *result,
1056 int row,
1057 const char *fname,
1058 size_t *dst_size,
1059 void *dst)
1060{
1061 uint64_t *udst = dst;
1062 const uint64_t *res;
1063 int fnum;
1064
1065 (void) cls;
1066 fnum = PQfnumber (result,
1067 fname);
1068 if (fnum < 0)
1069 {
1070 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1071 "Field %s missing in result\n",
1072 fname);
1073 GNUNET_break (0);
1074 return GNUNET_SYSERR;
1075 }
1076 if (PQgetisnull (result,
1077 row,
1078 fnum))
1079 return GNUNET_NO;
1080
1081 GNUNET_assert (NULL != dst);
1082 if (sizeof(uint64_t) != *dst_size)
1083 {
1084 GNUNET_break (0);
1085 return GNUNET_SYSERR;
1086 }
1087 if (sizeof(uint64_t) !=
1088 PQgetlength (result,
1089 row,
1090 fnum))
1091 {
1092 GNUNET_break (0);
1093 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1094 "Got length %u for field `%s'\n",
1095 PQgetlength (result,
1096 row,
1097 fnum),
1098 fname);
1099 return GNUNET_SYSERR;
1100 }
1101 res = (uint64_t *) PQgetvalue (result,
1102 row,
1103 fnum);
1104 *udst = GNUNET_ntohll (*res);
1105 return GNUNET_OK;
1106}
1107
1108
1109struct GNUNET_PQ_ResultSpec
1110GNUNET_PQ_result_spec_uint64 (const char *name,
1111 uint64_t *u64)
1112{
1113 struct GNUNET_PQ_ResultSpec res = {
1114 .conv = &extract_uint64,
1115 .dst = (void *) u64,
1116 .dst_size = sizeof(*u64),
1117 .fname = name
1118 };
1119
1120 return res;
1121}
1122
1123
1124/**
1125 * Closure for the array result specifications. Contains type information
1126 * for the generic parser extract_array_generic and out-pointers for the results.
1127 */
1128struct array_result_cls
1129{
1130 /* Oid of the expected type, must match the oid in the header of the PQResult struct */
1131 Oid oid;
1132
1133 /* Target type */
1134 enum array_types typ;
1135
1136 /* If not 0, defines the expected size of each entry */
1137 size_t same_size;
1138
1139 /* Out-pointer to write the number of elements in the array */
1140 size_t *num;
1141
1142 /* Out-pointer. If @a typ is array_of_byte and @a same_size is 0,
1143 * allocate and put the array of @a num sizes here. NULL otherwise */
1144 size_t **sizes;
1145};
1146
1147
1148/**
1149 * Extract data from a Postgres database @a result as array of a specific type
1150 * from row @a row. The type information and optionally additional
1151 * out-parameters are given in @a cls which is of type array_result_cls.
1152 *
1153 * @param cls closure of type array_result_cls
1154 * @param result where to extract data from
1155 * @param row row to extract data from
1156 * @param fname name (or prefix) of the fields to extract from
1157 * @param[in,out] dst_size where to store size of result, may be NULL
1158 * @param[out] dst where to store the result
1159 * @return
1160 * #GNUNET_YES if all results could be extracted
1161 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
1162 */
1163static enum GNUNET_GenericReturnValue
1164extract_array_generic (
1165 void *cls,
1166 PGresult *result,
1167 int row,
1168 const char *fname,
1169 size_t *dst_size,
1170 void *dst)
1171{
1172 const struct array_result_cls *info = cls;
1173 int data_sz;
1174 char *data;
1175 void *out = NULL;
1176 struct pq_array_header header;
1177 int col_num;
1178
1179 GNUNET_assert (NULL != dst);
1180 *((void **) dst) = NULL;
1181
1182 #define FAIL_IF(cond) \
1183 do { \
1184 if ((cond)) \
1185 { \
1186 GNUNET_break (! (cond)); \
1187 goto FAIL; \
1188 } \
1189 } while (0)
1190
1191 col_num = PQfnumber (result, fname);
1192 FAIL_IF (0 > col_num);
1193
1194 data_sz = PQgetlength (result, row, col_num);
1195 FAIL_IF (0 > data_sz);
1196 FAIL_IF (sizeof(header) > (size_t) data_sz);
1197
1198 data = PQgetvalue (result, row, col_num);
1199 FAIL_IF (NULL == data);
1200
1201 {
1202 struct pq_array_header *h =
1203 (struct pq_array_header *) data;
1204
1205 header.ndim = ntohl (h->ndim);
1206 header.has_null = ntohl (h->has_null);
1207 header.oid = ntohl (h->oid);
1208 header.dim = ntohl (h->dim);
1209 header.lbound = ntohl (h->lbound);
1210
1211 FAIL_IF (1 != header.ndim);
1212 FAIL_IF (INT_MAX <= header.dim);
1213 FAIL_IF (0 != header.has_null);
1214 FAIL_IF (1 != header.lbound);
1215 FAIL_IF (info->oid != header.oid);
1216 }
1217
1218 if (NULL != info->num)
1219 *info->num = header.dim;
1220
1221 {
1222 char *in = data + sizeof(header);
1223
1224 switch (info->typ)
1225 {
1226 case array_of_bool:
1227 if (NULL != dst_size)
1228 *dst_size = sizeof(bool) * (header.dim);
1229 out = GNUNET_new_array (header.dim, bool);
1230 *((void **) dst) = out;
1231 for (uint32_t i = 0; i < header.dim; i++)
1232 {
1233 size_t sz = ntohl (*(uint32_t *) in);
1234 FAIL_IF (sz != sizeof(bool));
1235 in += sizeof(uint32_t);
1236 *(bool *) out = *(bool *) in;
1237 in += sz;
1238 out += sz;
1239 }
1240 break;
1241
1242 case array_of_uint16:
1243 if (NULL != dst_size)
1244 *dst_size = sizeof(uint16_t) * (header.dim);
1245 out = GNUNET_new_array (header.dim, uint16_t);
1246 *((void **) dst) = out;
1247 for (uint32_t i = 0; i < header.dim; i++)
1248 {
1249 size_t sz = ntohl (*(uint32_t *) in);
1250 FAIL_IF (sz != sizeof(uint16_t));
1251 in += sizeof(uint32_t);
1252 *(uint16_t *) out = ntohs (*(uint16_t *) in);
1253 in += sz;
1254 out += sz;
1255 }
1256 break;
1257
1258 case array_of_uint32:
1259 if (NULL != dst_size)
1260 *dst_size = sizeof(uint32_t) * (header.dim);
1261 out = GNUNET_new_array (header.dim, uint32_t);
1262 *((void **) dst) = out;
1263 for (uint32_t i = 0; i < header.dim; i++)
1264 {
1265 size_t sz = ntohl (*(uint32_t *) in);
1266 FAIL_IF (sz != sizeof(uint32_t));
1267 in += sizeof(uint32_t);
1268 *(uint32_t *) out = ntohl (*(uint32_t *) in);
1269 in += sz;
1270 out += sz;
1271 }
1272 break;
1273
1274 case array_of_uint64:
1275 if (NULL != dst_size)
1276 *dst_size = sizeof(uint64_t) * (header.dim);
1277 out = GNUNET_new_array (header.dim, uint64_t);
1278 *((void **) dst) = out;
1279 for (uint32_t i = 0; i < header.dim; i++)
1280 {
1281 size_t sz = ntohl (*(uint32_t *) in);
1282 FAIL_IF (sz != sizeof(uint64_t));
1283 in += sizeof(uint32_t);
1284 *(uint64_t *) out = GNUNET_ntohll (*(uint64_t *) in);
1285 in += sz;
1286 out += sz;
1287 }
1288 break;
1289
1290 case array_of_abs_time:
1291 if (NULL != dst_size)
1292 *dst_size = sizeof(struct GNUNET_TIME_Absolute) * (header.dim);
1293 out = GNUNET_new_array (header.dim, struct GNUNET_TIME_Absolute);
1294 *((void **) dst) = out;
1295 for (uint32_t i = 0; i < header.dim; i++)
1296 {
1297 size_t sz = ntohl (*(uint32_t *) in);
1298 FAIL_IF (sz != sizeof(uint64_t));
1299 in += sizeof(uint32_t);
1300 ((struct GNUNET_TIME_Absolute *) out)->abs_value_us =
1301 GNUNET_ntohll (*(uint64_t *) in);
1302 in += sz;
1303 out += sz;
1304 }
1305 break;
1306
1307 case array_of_rel_time:
1308 if (NULL != dst_size)
1309 *dst_size = sizeof(struct GNUNET_TIME_Relative) * (header.dim);
1310 out = GNUNET_new_array (header.dim, struct GNUNET_TIME_Relative);
1311 *((void **) dst) = out;
1312 for (uint32_t i = 0; i < header.dim; i++)
1313 {
1314 size_t sz = ntohl (*(uint32_t *) in);
1315 FAIL_IF (sz != sizeof(uint64_t));
1316 in += sizeof(uint32_t);
1317 ((struct GNUNET_TIME_Relative *) out)->rel_value_us =
1318 GNUNET_ntohll (*(uint64_t *) in);
1319 in += sz;
1320 out += sz;
1321 }
1322 break;
1323
1324 case array_of_timestamp:
1325 if (NULL != dst_size)
1326 *dst_size = sizeof(struct GNUNET_TIME_Timestamp) * (header.dim);
1327 out = GNUNET_new_array (header.dim, struct GNUNET_TIME_Timestamp);
1328 *((void **) dst) = out;
1329 for (uint32_t i = 0; i < header.dim; i++)
1330 {
1331 size_t sz = ntohl (*(uint32_t *) in);
1332 FAIL_IF (sz != sizeof(uint64_t));
1333 in += sizeof(uint32_t);
1334 ((struct GNUNET_TIME_Timestamp *) out)->abs_time.abs_value_us =
1335 GNUNET_ntohll (*(uint64_t *) in);
1336 in += sz;
1337 out += sz;
1338 }
1339 break;
1340
1341 case array_of_byte:
1342 if (0 == info->same_size)
1343 *info->sizes = GNUNET_new_array (header.dim, size_t);
1344 /* fallthrough */
1345 case array_of_string:
1346 {
1347 size_t total = 0;
1348 bool is_string = (array_of_string == info->typ);
1349
1350 /* first, calculate total size required for allocation */
1351 {
1352 char *ptr = data + sizeof(header);
1353 for (uint32_t i = 0; i < header.dim; i++)
1354 {
1355 uint32_t sz;
1356
1357 sz = ntohl (*(uint32_t *) ptr);
1358 sz += is_string ? 1 : 0;
1359 total += sz;
1360 ptr += sizeof(uint32_t);
1361 ptr += sz;
1362
1363 if ((! is_string) &&
1364 (0 == info->same_size))
1365 (*info->sizes)[i] = sz;
1366
1367 FAIL_IF ((0 != info->same_size) &&
1368 (sz != info->same_size));
1369 FAIL_IF (total < sz);
1370 }
1371 }
1372
1373 if (NULL != dst_size)
1374 *dst_size = total;
1375
1376 FAIL_IF (0 == total);
1377 out = GNUNET_malloc (total);
1378
1379 *((void **) dst) = out;
1380
1381 /* copy data */
1382 for (uint32_t i = 0; i < header.dim; i++)
1383 {
1384 size_t sz = ntohl (*(uint32_t *) in);
1385 in += sizeof(uint32_t);
1386 GNUNET_memcpy (out, in, sz);
1387
1388 in += sz;
1389 out += sz;
1390 out += (array_of_string == info->typ) ? 1 : 0;
1391 }
1392 break;
1393 }
1394 default:
1395 FAIL_IF (1 != 0);
1396 }
1397 }
1398
1399 return GNUNET_OK;
1400
1401FAIL:
1402 GNUNET_free (*(void **) dst);
1403 return GNUNET_SYSERR;
1404 #undef FAIL_IF
1405}
1406
1407
1408/**
1409 * Cleanup of the data and closure of an array spec.
1410 */
1411static void
1412array_cleanup (void *cls,
1413 void *rd)
1414{
1415
1416 struct array_result_cls *info = cls;
1417 void **dst = rd;
1418
1419 if ((array_of_byte == info->typ) &&
1420 (0 == info->same_size) &&
1421 (NULL != info->sizes))
1422 GNUNET_free (*(info->sizes));
1423
1424 GNUNET_free (cls);
1425 GNUNET_free (*dst);
1426 *dst = NULL;
1427}
1428
1429
1430struct GNUNET_PQ_ResultSpec
1431GNUNET_PQ_result_spec_array_bool (
1432 struct GNUNET_PQ_Context *db,
1433 const char *name,
1434 size_t *num,
1435 bool **dst)
1436{
1437 struct array_result_cls *info =
1438 GNUNET_new (struct array_result_cls);
1439
1440 info->num = num;
1441 info->typ = array_of_bool;
1442 GNUNET_assert (GNUNET_OK ==
1443 GNUNET_PQ_get_oid_by_name (db,
1444 "bool",
1445 &info->oid));
1446
1447 struct GNUNET_PQ_ResultSpec res = {
1448 .conv = extract_array_generic,
1449 .cleaner = array_cleanup,
1450 .dst = (void *) dst,
1451 .fname = name,
1452 .cls = info
1453 };
1454 return res;
1455}
1456
1457
1458struct GNUNET_PQ_ResultSpec
1459GNUNET_PQ_result_spec_array_uint16 (
1460 struct GNUNET_PQ_Context *db,
1461 const char *name,
1462 size_t *num,
1463 uint16_t **dst)
1464{
1465 struct array_result_cls *info =
1466 GNUNET_new (struct array_result_cls);
1467
1468 info->num = num;
1469 info->typ = array_of_uint16;
1470 GNUNET_assert (GNUNET_OK ==
1471 GNUNET_PQ_get_oid_by_name (db,
1472 "int2",
1473 &info->oid));
1474
1475 struct GNUNET_PQ_ResultSpec res = {
1476 .conv = extract_array_generic,
1477 .cleaner = array_cleanup,
1478 .dst = (void *) dst,
1479 .fname = name,
1480 .cls = info
1481 };
1482 return res;
1483}
1484
1485
1486struct GNUNET_PQ_ResultSpec
1487GNUNET_PQ_result_spec_array_uint32 (
1488 struct GNUNET_PQ_Context *db,
1489 const char *name,
1490 size_t *num,
1491 uint32_t **dst)
1492{
1493 struct array_result_cls *info =
1494 GNUNET_new (struct array_result_cls);
1495
1496 info->num = num;
1497 info->typ = array_of_uint32;
1498 GNUNET_assert (GNUNET_OK ==
1499 GNUNET_PQ_get_oid_by_name (db,
1500 "int4",
1501 &info->oid));
1502
1503 struct GNUNET_PQ_ResultSpec res = {
1504 .conv = extract_array_generic,
1505 .cleaner = array_cleanup,
1506 .dst = (void *) dst,
1507 .fname = name,
1508 .cls = info
1509 };
1510 return res;
1511}
1512
1513
1514struct GNUNET_PQ_ResultSpec
1515GNUNET_PQ_result_spec_array_uint64 (
1516 struct GNUNET_PQ_Context *db,
1517 const char *name,
1518 size_t *num,
1519 uint64_t **dst)
1520{
1521 struct array_result_cls *info =
1522 GNUNET_new (struct array_result_cls);
1523
1524 info->num = num;
1525 info->typ = array_of_uint64;
1526 GNUNET_assert (GNUNET_OK ==
1527 GNUNET_PQ_get_oid_by_name (db,
1528 "int8",
1529 &info->oid));
1530
1531 struct GNUNET_PQ_ResultSpec res = {
1532 .conv = extract_array_generic,
1533 .cleaner = array_cleanup,
1534 .dst = (void *) dst,
1535 .fname = name,
1536 .cls = info
1537 };
1538 return res;
1539}
1540
1541
1542struct GNUNET_PQ_ResultSpec
1543GNUNET_PQ_result_spec_array_abs_time (
1544 struct GNUNET_PQ_Context *db,
1545 const char *name,
1546 size_t *num,
1547 struct GNUNET_TIME_Absolute **dst)
1548{
1549 struct array_result_cls *info =
1550 GNUNET_new (struct array_result_cls);
1551
1552 info->num = num;
1553 info->typ = array_of_abs_time;
1554 GNUNET_assert (GNUNET_OK ==
1555 GNUNET_PQ_get_oid_by_name (db,
1556 "int8",
1557 &info->oid));
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_rel_time (
1572 struct GNUNET_PQ_Context *db,
1573 const char *name,
1574 size_t *num,
1575 struct GNUNET_TIME_Relative **dst)
1576{
1577 struct array_result_cls *info =
1578 GNUNET_new (struct array_result_cls);
1579
1580 info->num = num;
1581 info->typ = array_of_rel_time;
1582 GNUNET_assert (GNUNET_OK ==
1583 GNUNET_PQ_get_oid_by_name (db,
1584 "int8",
1585 &info->oid));
1586
1587 struct GNUNET_PQ_ResultSpec res = {
1588 .conv = extract_array_generic,
1589 .cleaner = array_cleanup,
1590 .dst = (void *) dst,
1591 .fname = name,
1592 .cls = info
1593 };
1594 return res;
1595}
1596
1597
1598struct GNUNET_PQ_ResultSpec
1599GNUNET_PQ_result_spec_array_timestamp (
1600 struct GNUNET_PQ_Context *db,
1601 const char *name,
1602 size_t *num,
1603 struct GNUNET_TIME_Timestamp **dst)
1604{
1605 struct array_result_cls *info =
1606 GNUNET_new (struct array_result_cls);
1607
1608 info->num = num;
1609 info->typ = array_of_timestamp;
1610 GNUNET_assert (GNUNET_OK ==
1611 GNUNET_PQ_get_oid_by_name (db,
1612 "int8",
1613 &info->oid));
1614
1615 struct GNUNET_PQ_ResultSpec res = {
1616 .conv = extract_array_generic,
1617 .cleaner = array_cleanup,
1618 .dst = (void *) dst,
1619 .fname = name,
1620 .cls = info
1621 };
1622 return res;
1623}
1624
1625
1626struct GNUNET_PQ_ResultSpec
1627GNUNET_PQ_result_spec_array_variable_size (
1628 struct GNUNET_PQ_Context *db,
1629 const char *name,
1630 size_t *num,
1631 size_t **sizes,
1632 void **dst)
1633{
1634 struct array_result_cls *info =
1635 GNUNET_new (struct array_result_cls);
1636
1637 info->num = num;
1638 info->sizes = sizes;
1639 info->typ = array_of_byte;
1640 GNUNET_assert (GNUNET_OK ==
1641 GNUNET_PQ_get_oid_by_name (db,
1642 "bytea",
1643 &info->oid));
1644
1645 struct GNUNET_PQ_ResultSpec res = {
1646 .conv = extract_array_generic,
1647 .cleaner = array_cleanup,
1648 .dst = (void *) dst,
1649 .fname = name,
1650 .cls = info
1651 };
1652 return res;
1653}
1654
1655
1656struct GNUNET_PQ_ResultSpec
1657GNUNET_PQ_result_spec_array_fixed_size (
1658 struct GNUNET_PQ_Context *db,
1659 const char *name,
1660 size_t size,
1661 size_t *num,
1662 void **dst)
1663{
1664 struct array_result_cls *info =
1665 GNUNET_new (struct array_result_cls);
1666
1667 info->num = num;
1668 info->same_size = size;
1669 info->typ = array_of_byte;
1670 GNUNET_assert (GNUNET_OK ==
1671 GNUNET_PQ_get_oid_by_name (db,
1672 "bytea",
1673 &info->oid));
1674
1675 struct GNUNET_PQ_ResultSpec res = {
1676 .conv = extract_array_generic,
1677 .cleaner = array_cleanup,
1678 .dst = (void *) dst,
1679 .fname = name,
1680 .cls = info
1681 };
1682 return res;
1683}
1684
1685
1686struct GNUNET_PQ_ResultSpec
1687GNUNET_PQ_result_spec_array_string (
1688 struct GNUNET_PQ_Context *db,
1689 const char *name,
1690 size_t *num,
1691 char **dst)
1692{
1693 struct array_result_cls *info =
1694 GNUNET_new (struct array_result_cls);
1695
1696 info->num = num;
1697 info->typ = array_of_string;
1698 GNUNET_assert (GNUNET_OK ==
1699 GNUNET_PQ_get_oid_by_name (db,
1700 "text",
1701 &info->oid));
1702
1703 struct GNUNET_PQ_ResultSpec res = {
1704 .conv = extract_array_generic,
1705 .cleaner = array_cleanup,
1706 .dst = (void *) dst,
1707 .fname = name,
1708 .cls = info
1709 };
1710 return res;
1711}
1712
1713
1714/* end of pq_result_helper.c */