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.c2067
1 files changed, 2067 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..cbb1e8e8e
--- /dev/null
+++ b/src/lib/pq/pq_result_helper.c
@@ -0,0 +1,2067 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014-2024 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 * Extract data from a Postgres database @a result at row @a row.
1126 *
1127 * @param cls closure
1128 * @param result where to extract data from
1129 * @param row row to extract data from
1130 * @param fname name (or prefix) of the fields to extract from
1131 * @param[in,out] dst_size where to store size of result, may be NULL
1132 * @param[out] dst where to store the result
1133 * @return
1134 * #GNUNET_YES if all results could be extracted
1135 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
1136 */
1137static enum GNUNET_GenericReturnValue
1138extract_int64 (void *cls,
1139 PGresult *result,
1140 int row,
1141 const char *fname,
1142 size_t *dst_size,
1143 void *dst)
1144{
1145 int64_t *udst = dst;
1146 const int64_t *res;
1147 int fnum;
1148
1149 (void) cls;
1150 fnum = PQfnumber (result,
1151 fname);
1152 if (fnum < 0)
1153 {
1154 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1155 "Field %s missing in result\n",
1156 fname);
1157 GNUNET_break (0);
1158 return GNUNET_SYSERR;
1159 }
1160 if (PQgetisnull (result,
1161 row,
1162 fnum))
1163 return GNUNET_NO;
1164
1165 GNUNET_assert (NULL != dst);
1166 if (sizeof(int64_t) != *dst_size)
1167 {
1168 GNUNET_break (0);
1169 return GNUNET_SYSERR;
1170 }
1171 if (sizeof(int64_t) !=
1172 PQgetlength (result,
1173 row,
1174 fnum))
1175 {
1176 GNUNET_break (0);
1177 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1178 "Got length %u for field `%s'\n",
1179 PQgetlength (result,
1180 row,
1181 fnum),
1182 fname);
1183 return GNUNET_SYSERR;
1184 }
1185 res = (int64_t *) PQgetvalue (result,
1186 row,
1187 fnum);
1188 *udst = GNUNET_ntohll (*res);
1189 return GNUNET_OK;
1190}
1191
1192
1193struct GNUNET_PQ_ResultSpec
1194GNUNET_PQ_result_spec_int64 (const char *name,
1195 int64_t *i64)
1196{
1197 struct GNUNET_PQ_ResultSpec res = {
1198 .conv = &extract_int64,
1199 .dst = (void *) i64,
1200 .dst_size = sizeof(*i64),
1201 .fname = name
1202 };
1203
1204 return res;
1205}
1206
1207
1208/**
1209 * Closure for the array result specifications. Contains type information
1210 * for the generic parser extract_array_generic and out-pointers for the results.
1211 */
1212struct array_result_cls
1213{
1214 /* Oid of the expected type, must match the oid in the header of the PQResult struct */
1215 Oid oid;
1216
1217 /* Target type */
1218 enum array_types typ;
1219
1220 /* If not 0, defines the expected size of each entry */
1221 size_t same_size;
1222
1223 /* Out-pointer to write the number of elements in the array */
1224 size_t *num;
1225
1226 /* Out-pointer. If @a typ is array_of_byte and @a same_size is 0,
1227 * allocate and put the array of @a num sizes here. NULL otherwise */
1228 size_t **sizes;
1229};
1230
1231
1232/**
1233 * Extract data from a Postgres database @a result as array of a specific type
1234 * from row @a row. The type information and optionally additional
1235 * out-parameters are given in @a cls which is of type array_result_cls.
1236 *
1237 * @param cls closure of type array_result_cls
1238 * @param result where to extract data from
1239 * @param row row to extract data from
1240 * @param fname name (or prefix) of the fields to extract from
1241 * @param[in,out] dst_size where to store size of result, may be NULL
1242 * @param[out] dst where to store the result
1243 * @return
1244 * #GNUNET_YES if all results could be extracted
1245 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
1246 */
1247static enum GNUNET_GenericReturnValue
1248extract_array_generic (
1249 void *cls,
1250 PGresult *result,
1251 int row,
1252 const char *fname,
1253 size_t *dst_size,
1254 void *dst)
1255{
1256 const struct array_result_cls *info = cls;
1257 int data_sz;
1258 char *data;
1259 void *out = NULL;
1260 struct pq_array_header header;
1261 int col_num;
1262
1263 GNUNET_assert (NULL != dst);
1264 *((void **) dst) = NULL;
1265
1266 #define FAIL_IF(cond) \
1267 do { \
1268 if ((cond)) \
1269 { \
1270 GNUNET_break (! (cond)); \
1271 goto FAIL; \
1272 } \
1273 } while (0)
1274
1275 col_num = PQfnumber (result, fname);
1276 FAIL_IF (0 > col_num);
1277
1278 data_sz = PQgetlength (result, row, col_num);
1279 FAIL_IF (0 > data_sz);
1280 FAIL_IF (sizeof(header) > (size_t) data_sz);
1281
1282 data = PQgetvalue (result, row, col_num);
1283 FAIL_IF (NULL == data);
1284
1285 {
1286 struct pq_array_header *h =
1287 (struct pq_array_header *) data;
1288
1289 header.ndim = ntohl (h->ndim);
1290 header.has_null = ntohl (h->has_null);
1291 header.oid = ntohl (h->oid);
1292 header.dim = ntohl (h->dim);
1293 header.lbound = ntohl (h->lbound);
1294
1295 FAIL_IF (1 != header.ndim);
1296 FAIL_IF (INT_MAX <= header.dim);
1297 FAIL_IF (0 != header.has_null);
1298 FAIL_IF (1 != header.lbound);
1299 FAIL_IF (info->oid != header.oid);
1300 }
1301
1302 if (NULL != info->num)
1303 *info->num = header.dim;
1304
1305 {
1306 char *in = data + sizeof(header);
1307
1308 switch (info->typ)
1309 {
1310 case array_of_bool:
1311 if (NULL != dst_size)
1312 *dst_size = sizeof(bool) * (header.dim);
1313 out = GNUNET_new_array (header.dim, bool);
1314 *((void **) dst) = out;
1315 for (uint32_t i = 0; i < header.dim; i++)
1316 {
1317 size_t sz = ntohl (*(uint32_t *) in);
1318 FAIL_IF (sz != sizeof(bool));
1319 in += sizeof(uint32_t);
1320 *(bool *) out = *(bool *) in;
1321 in += sz;
1322 out += sz;
1323 }
1324 break;
1325
1326 case array_of_uint16:
1327 if (NULL != dst_size)
1328 *dst_size = sizeof(uint16_t) * (header.dim);
1329 out = GNUNET_new_array (header.dim, uint16_t);
1330 *((void **) dst) = out;
1331 for (uint32_t i = 0; i < header.dim; i++)
1332 {
1333 size_t sz = ntohl (*(uint32_t *) in);
1334 FAIL_IF (sz != sizeof(uint16_t));
1335 in += sizeof(uint32_t);
1336 *(uint16_t *) out = ntohs (*(uint16_t *) in);
1337 in += sz;
1338 out += sz;
1339 }
1340 break;
1341
1342 case array_of_uint32:
1343 if (NULL != dst_size)
1344 *dst_size = sizeof(uint32_t) * (header.dim);
1345 out = GNUNET_new_array (header.dim, uint32_t);
1346 *((void **) dst) = out;
1347 for (uint32_t i = 0; i < header.dim; i++)
1348 {
1349 size_t sz = ntohl (*(uint32_t *) in);
1350 FAIL_IF (sz != sizeof(uint32_t));
1351 in += sizeof(uint32_t);
1352 *(uint32_t *) out = ntohl (*(uint32_t *) in);
1353 in += sz;
1354 out += sz;
1355 }
1356 break;
1357
1358 case array_of_uint64:
1359 if (NULL != dst_size)
1360 *dst_size = sizeof(uint64_t) * (header.dim);
1361 out = GNUNET_new_array (header.dim, uint64_t);
1362 *((void **) dst) = out;
1363 for (uint32_t i = 0; i < header.dim; i++)
1364 {
1365 size_t sz = ntohl (*(uint32_t *) in);
1366 FAIL_IF (sz != sizeof(uint64_t));
1367 in += sizeof(uint32_t);
1368 *(uint64_t *) out = GNUNET_ntohll (*(uint64_t *) in);
1369 in += sz;
1370 out += sz;
1371 }
1372 break;
1373
1374 case array_of_abs_time:
1375 if (NULL != dst_size)
1376 *dst_size = sizeof(struct GNUNET_TIME_Absolute) * (header.dim);
1377 out = GNUNET_new_array (header.dim, struct GNUNET_TIME_Absolute);
1378 *((void **) dst) = out;
1379 for (uint32_t i = 0; i < header.dim; i++)
1380 {
1381 size_t sz = ntohl (*(uint32_t *) in);
1382 FAIL_IF (sz != sizeof(uint64_t));
1383 in += sizeof(uint32_t);
1384 ((struct GNUNET_TIME_Absolute *) out)->abs_value_us =
1385 GNUNET_ntohll (*(uint64_t *) in);
1386 in += sz;
1387 out += sz;
1388 }
1389 break;
1390
1391 case array_of_rel_time:
1392 if (NULL != dst_size)
1393 *dst_size = sizeof(struct GNUNET_TIME_Relative) * (header.dim);
1394 out = GNUNET_new_array (header.dim, struct GNUNET_TIME_Relative);
1395 *((void **) dst) = out;
1396 for (uint32_t i = 0; i < header.dim; i++)
1397 {
1398 size_t sz = ntohl (*(uint32_t *) in);
1399 FAIL_IF (sz != sizeof(uint64_t));
1400 in += sizeof(uint32_t);
1401 ((struct GNUNET_TIME_Relative *) out)->rel_value_us =
1402 GNUNET_ntohll (*(uint64_t *) in);
1403 in += sz;
1404 out += sz;
1405 }
1406 break;
1407
1408 case array_of_timestamp:
1409 if (NULL != dst_size)
1410 *dst_size = sizeof(struct GNUNET_TIME_Timestamp) * (header.dim);
1411 out = GNUNET_new_array (header.dim, struct GNUNET_TIME_Timestamp);
1412 *((void **) dst) = out;
1413 for (uint32_t i = 0; i < header.dim; i++)
1414 {
1415 size_t sz = ntohl (*(uint32_t *) in);
1416 FAIL_IF (sz != sizeof(uint64_t));
1417 in += sizeof(uint32_t);
1418 ((struct GNUNET_TIME_Timestamp *) out)->abs_time.abs_value_us =
1419 GNUNET_ntohll (*(uint64_t *) in);
1420 in += sz;
1421 out += sz;
1422 }
1423 break;
1424
1425 case array_of_byte:
1426 if (0 == info->same_size)
1427 *info->sizes = GNUNET_new_array (header.dim, size_t);
1428 /* fallthrough */
1429 case array_of_string:
1430 {
1431 size_t total = 0;
1432 bool is_string = (array_of_string == info->typ);
1433
1434 /* first, calculate total size required for allocation */
1435 {
1436 char *ptr = data + sizeof(header);
1437 for (uint32_t i = 0; i < header.dim; i++)
1438 {
1439 uint32_t sz;
1440
1441 sz = ntohl (*(uint32_t *) ptr);
1442 sz += is_string ? 1 : 0;
1443 total += sz;
1444 ptr += sizeof(uint32_t);
1445 ptr += sz;
1446
1447 if ((! is_string) &&
1448 (0 == info->same_size))
1449 (*info->sizes)[i] = sz;
1450
1451 FAIL_IF ((0 != info->same_size) &&
1452 (sz != info->same_size));
1453 FAIL_IF (total < sz);
1454 }
1455 }
1456
1457 if (NULL != dst_size)
1458 *dst_size = total;
1459
1460 FAIL_IF (0 == total);
1461 out = GNUNET_malloc (total);
1462
1463 *((void **) dst) = out;
1464
1465 /* copy data */
1466 for (uint32_t i = 0; i < header.dim; i++)
1467 {
1468 size_t sz = ntohl (*(uint32_t *) in);
1469 in += sizeof(uint32_t);
1470 GNUNET_memcpy (out, in, sz);
1471
1472 in += sz;
1473 out += sz;
1474 out += (array_of_string == info->typ) ? 1 : 0;
1475 }
1476 break;
1477 }
1478 default:
1479 FAIL_IF (1 != 0);
1480 }
1481 }
1482
1483 return GNUNET_OK;
1484
1485FAIL:
1486 GNUNET_free (*(void **) dst);
1487 return GNUNET_SYSERR;
1488 #undef FAIL_IF
1489}
1490
1491
1492/**
1493 * Cleanup of the data and closure of an array spec.
1494 */
1495static void
1496array_cleanup (void *cls,
1497 void *rd)
1498{
1499
1500 struct array_result_cls *info = cls;
1501 void **dst = rd;
1502
1503 if ((array_of_byte == info->typ) &&
1504 (0 == info->same_size) &&
1505 (NULL != info->sizes))
1506 GNUNET_free (*(info->sizes));
1507
1508 GNUNET_free (cls);
1509 GNUNET_free (*dst);
1510 *dst = NULL;
1511}
1512
1513
1514struct GNUNET_PQ_ResultSpec
1515GNUNET_PQ_result_spec_array_bool (
1516 struct GNUNET_PQ_Context *db,
1517 const char *name,
1518 size_t *num,
1519 bool **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_bool;
1526 GNUNET_assert (GNUNET_OK ==
1527 GNUNET_PQ_get_oid_by_name (db,
1528 "bool",
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_uint16 (
1544 struct GNUNET_PQ_Context *db,
1545 const char *name,
1546 size_t *num,
1547 uint16_t **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_uint16;
1554 GNUNET_assert (GNUNET_OK ==
1555 GNUNET_PQ_get_oid_by_name (db,
1556 "int2",
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_uint32 (
1572 struct GNUNET_PQ_Context *db,
1573 const char *name,
1574 size_t *num,
1575 uint32_t **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_uint32;
1582 GNUNET_assert (GNUNET_OK ==
1583 GNUNET_PQ_get_oid_by_name (db,
1584 "int4",
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_uint64 (
1600 struct GNUNET_PQ_Context *db,
1601 const char *name,
1602 size_t *num,
1603 uint64_t **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_uint64;
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_abs_time (
1628 struct GNUNET_PQ_Context *db,
1629 const char *name,
1630 size_t *num,
1631 struct GNUNET_TIME_Absolute **dst)
1632{
1633 struct array_result_cls *info =
1634 GNUNET_new (struct array_result_cls);
1635
1636 info->num = num;
1637 info->typ = array_of_abs_time;
1638 GNUNET_assert (GNUNET_OK ==
1639 GNUNET_PQ_get_oid_by_name (db,
1640 "int8",
1641 &info->oid));
1642
1643 struct GNUNET_PQ_ResultSpec res = {
1644 .conv = extract_array_generic,
1645 .cleaner = array_cleanup,
1646 .dst = (void *) dst,
1647 .fname = name,
1648 .cls = info
1649 };
1650 return res;
1651}
1652
1653
1654struct GNUNET_PQ_ResultSpec
1655GNUNET_PQ_result_spec_array_rel_time (
1656 struct GNUNET_PQ_Context *db,
1657 const char *name,
1658 size_t *num,
1659 struct GNUNET_TIME_Relative **dst)
1660{
1661 struct array_result_cls *info =
1662 GNUNET_new (struct array_result_cls);
1663
1664 info->num = num;
1665 info->typ = array_of_rel_time;
1666 GNUNET_assert (GNUNET_OK ==
1667 GNUNET_PQ_get_oid_by_name (db,
1668 "int8",
1669 &info->oid));
1670
1671 struct GNUNET_PQ_ResultSpec res = {
1672 .conv = extract_array_generic,
1673 .cleaner = array_cleanup,
1674 .dst = (void *) dst,
1675 .fname = name,
1676 .cls = info
1677 };
1678 return res;
1679}
1680
1681
1682struct GNUNET_PQ_ResultSpec
1683GNUNET_PQ_result_spec_array_timestamp (
1684 struct GNUNET_PQ_Context *db,
1685 const char *name,
1686 size_t *num,
1687 struct GNUNET_TIME_Timestamp **dst)
1688{
1689 struct array_result_cls *info =
1690 GNUNET_new (struct array_result_cls);
1691
1692 info->num = num;
1693 info->typ = array_of_timestamp;
1694 GNUNET_assert (GNUNET_OK ==
1695 GNUNET_PQ_get_oid_by_name (db,
1696 "int8",
1697 &info->oid));
1698
1699 struct GNUNET_PQ_ResultSpec res = {
1700 .conv = extract_array_generic,
1701 .cleaner = array_cleanup,
1702 .dst = (void *) dst,
1703 .fname = name,
1704 .cls = info
1705 };
1706 return res;
1707}
1708
1709
1710struct GNUNET_PQ_ResultSpec
1711GNUNET_PQ_result_spec_array_variable_size (
1712 struct GNUNET_PQ_Context *db,
1713 const char *name,
1714 size_t *num,
1715 size_t **sizes,
1716 void **dst)
1717{
1718 struct array_result_cls *info =
1719 GNUNET_new (struct array_result_cls);
1720
1721 info->num = num;
1722 info->sizes = sizes;
1723 info->typ = array_of_byte;
1724 GNUNET_assert (GNUNET_OK ==
1725 GNUNET_PQ_get_oid_by_name (db,
1726 "bytea",
1727 &info->oid));
1728
1729 struct GNUNET_PQ_ResultSpec res = {
1730 .conv = extract_array_generic,
1731 .cleaner = array_cleanup,
1732 .dst = (void *) dst,
1733 .fname = name,
1734 .cls = info
1735 };
1736 return res;
1737}
1738
1739
1740struct GNUNET_PQ_ResultSpec
1741GNUNET_PQ_result_spec_array_fixed_size (
1742 struct GNUNET_PQ_Context *db,
1743 const char *name,
1744 size_t size,
1745 size_t *num,
1746 void **dst)
1747{
1748 struct array_result_cls *info =
1749 GNUNET_new (struct array_result_cls);
1750
1751 info->num = num;
1752 info->same_size = size;
1753 info->typ = array_of_byte;
1754 GNUNET_assert (GNUNET_OK ==
1755 GNUNET_PQ_get_oid_by_name (db,
1756 "bytea",
1757 &info->oid));
1758
1759 struct GNUNET_PQ_ResultSpec res = {
1760 .conv = extract_array_generic,
1761 .cleaner = array_cleanup,
1762 .dst = (void *) dst,
1763 .fname = name,
1764 .cls = info
1765 };
1766 return res;
1767}
1768
1769
1770struct GNUNET_PQ_ResultSpec
1771GNUNET_PQ_result_spec_array_string (
1772 struct GNUNET_PQ_Context *db,
1773 const char *name,
1774 size_t *num,
1775 char **dst)
1776{
1777 struct array_result_cls *info =
1778 GNUNET_new (struct array_result_cls);
1779
1780 info->num = num;
1781 info->typ = array_of_string;
1782 GNUNET_assert (GNUNET_OK ==
1783 GNUNET_PQ_get_oid_by_name (db,
1784 "text",
1785 &info->oid));
1786
1787 struct GNUNET_PQ_ResultSpec res = {
1788 .conv = extract_array_generic,
1789 .cleaner = array_cleanup,
1790 .dst = (void *) dst,
1791 .fname = name,
1792 .cls = info
1793 };
1794 return res;
1795}
1796
1797
1798/**
1799 * Extract data from a Postgres database @a result at row @a row.
1800 *
1801 * @param cls closure
1802 * @param result where to extract data from
1803 * @param row the row to extract data from
1804 * @param fname name (or prefix) of the fields to extract from
1805 * @param[in,out] dst_size where to store size of result, may be NULL
1806 * @param[out] dst where to store the result
1807 * @return
1808 * #GNUNET_YES if all results could be extracted
1809 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
1810 */
1811static enum GNUNET_GenericReturnValue
1812extract_blind_sign_pub (void *cls,
1813 PGresult *result,
1814 int row,
1815 const char *fname,
1816 size_t *dst_size,
1817 void *dst)
1818{
1819 struct GNUNET_CRYPTO_BlindSignPublicKey **bpk = dst;
1820 struct GNUNET_CRYPTO_BlindSignPublicKey *tmp;
1821 size_t len;
1822 const char *res;
1823 int fnum;
1824 uint32_t be;
1825
1826 (void) cls;
1827 (void) dst_size;
1828 fnum = PQfnumber (result,
1829 fname);
1830 if (fnum < 0)
1831 {
1832 GNUNET_break (0);
1833 return GNUNET_SYSERR;
1834 }
1835 if (PQgetisnull (result,
1836 row,
1837 fnum))
1838 return GNUNET_NO;
1839
1840 /* if a field is null, continue but
1841 * remember that we now return a different result */
1842 len = PQgetlength (result,
1843 row,
1844 fnum);
1845 res = PQgetvalue (result,
1846 row,
1847 fnum);
1848 if (len < sizeof (be))
1849 {
1850 GNUNET_break (0);
1851 return GNUNET_SYSERR;
1852 }
1853 GNUNET_memcpy (&be,
1854 res,
1855 sizeof (be));
1856 res += sizeof (be);
1857 len -= sizeof (be);
1858 tmp = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
1859 tmp->cipher = ntohl (be);
1860 tmp->rc = 1;
1861 switch (tmp->cipher)
1862 {
1863 case GNUNET_CRYPTO_BSA_INVALID:
1864 break;
1865 case GNUNET_CRYPTO_BSA_RSA:
1866 tmp->details.rsa_public_key
1867 = GNUNET_CRYPTO_rsa_public_key_decode (res,
1868 len);
1869 if (NULL == tmp->details.rsa_public_key)
1870 {
1871 GNUNET_break (0);
1872 GNUNET_free (tmp);
1873 return GNUNET_SYSERR;
1874 }
1875 GNUNET_CRYPTO_hash (res,
1876 len,
1877 &tmp->pub_key_hash);
1878 *bpk = tmp;
1879 return GNUNET_OK;
1880 case GNUNET_CRYPTO_BSA_CS:
1881 if (sizeof (tmp->details.cs_public_key) != len)
1882 {
1883 GNUNET_break (0);
1884 GNUNET_free (tmp);
1885 return GNUNET_SYSERR;
1886 }
1887 GNUNET_memcpy (&tmp->details.cs_public_key,
1888 res,
1889 len);
1890 GNUNET_CRYPTO_hash (res,
1891 len,
1892 &tmp->pub_key_hash);
1893 *bpk = tmp;
1894 return GNUNET_OK;
1895 }
1896 GNUNET_break (0);
1897 GNUNET_free (tmp);
1898 return GNUNET_SYSERR;
1899}
1900
1901
1902/**
1903 * Function called to clean up memory allocated
1904 * by a #GNUNET_PQ_ResultConverter.
1905 *
1906 * @param cls closure
1907 * @param rd result data to clean up
1908 */
1909static void
1910clean_blind_sign_pub (void *cls,
1911 void *rd)
1912{
1913 struct GNUNET_CRYPTO_BlindSignPublicKey **pub = rd;
1914
1915 (void) cls;
1916 GNUNET_CRYPTO_blind_sign_pub_decref (*pub);
1917 *pub = NULL;
1918}
1919
1920
1921struct GNUNET_PQ_ResultSpec
1922GNUNET_PQ_result_spec_blind_sign_pub (const char *name,
1923 struct GNUNET_CRYPTO_BlindSignPublicKey **pub)
1924{
1925 struct GNUNET_PQ_ResultSpec res = {
1926 .conv = &extract_blind_sign_pub,
1927 .cleaner = &clean_blind_sign_pub,
1928 .dst = (void *) pub,
1929 .fname = name
1930 };
1931
1932 return res;
1933}
1934
1935
1936/**
1937 * Extract data from a Postgres database @a result at row @a row.
1938 *
1939 * @param cls closure
1940 * @param result where to extract data from
1941 * @param row the row to extract data from
1942 * @param fname name (or prefix) of the fields to extract from
1943 * @param[in,out] dst_size where to store size of result, may be NULL
1944 * @param[out] dst where to store the result
1945 * @return
1946 * #GNUNET_YES if all results could be extracted
1947 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
1948 */
1949static enum GNUNET_GenericReturnValue
1950extract_blind_sign_priv (void *cls,
1951 PGresult *result,
1952 int row,
1953 const char *fname,
1954 size_t *dst_size,
1955 void *dst)
1956{
1957 struct GNUNET_CRYPTO_BlindSignPrivateKey **bpk = dst;
1958 struct GNUNET_CRYPTO_BlindSignPrivateKey *tmp;
1959 size_t len;
1960 const char *res;
1961 int fnum;
1962 uint32_t be;
1963
1964 (void) cls;
1965 (void) dst_size;
1966 fnum = PQfnumber (result,
1967 fname);
1968 if (fnum < 0)
1969 {
1970 GNUNET_break (0);
1971 return GNUNET_SYSERR;
1972 }
1973 if (PQgetisnull (result,
1974 row,
1975 fnum))
1976 return GNUNET_NO;
1977
1978 /* if a field is null, continue but
1979 * remember that we now return a different result */
1980 len = PQgetlength (result,
1981 row,
1982 fnum);
1983 res = PQgetvalue (result,
1984 row,
1985 fnum);
1986 if (len < sizeof (be))
1987 {
1988 GNUNET_break (0);
1989 return GNUNET_SYSERR;
1990 }
1991 GNUNET_memcpy (&be,
1992 res,
1993 sizeof (be));
1994 res += sizeof (be);
1995 len -= sizeof (be);
1996 tmp = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPrivateKey);
1997 tmp->cipher = ntohl (be);
1998 tmp->rc = 1;
1999 switch (tmp->cipher)
2000 {
2001 case GNUNET_CRYPTO_BSA_INVALID:
2002 break;
2003 case GNUNET_CRYPTO_BSA_RSA:
2004 tmp->details.rsa_private_key
2005 = GNUNET_CRYPTO_rsa_private_key_decode (res,
2006 len);
2007 if (NULL == tmp->details.rsa_private_key)
2008 {
2009 GNUNET_break (0);
2010 GNUNET_free (bpk);
2011 return GNUNET_SYSERR;
2012 }
2013 *bpk = tmp;
2014 return GNUNET_OK;
2015 case GNUNET_CRYPTO_BSA_CS:
2016 if (sizeof (tmp->details.cs_private_key) != len)
2017 {
2018 GNUNET_break (0);
2019 GNUNET_free (tmp);
2020 return GNUNET_SYSERR;
2021 }
2022 GNUNET_memcpy (&tmp->details.cs_private_key,
2023 res,
2024 len);
2025 *bpk = tmp;
2026 return GNUNET_OK;
2027 }
2028 GNUNET_break (0);
2029 GNUNET_free (tmp);
2030 return GNUNET_SYSERR;
2031}
2032
2033
2034/**
2035 * Function called to clean up memory allocated
2036 * by a #GNUNET_PQ_ResultConverter.
2037 *
2038 * @param cls closure
2039 * @param rd result data to clean up
2040 */
2041static void
2042clean_blind_sign_priv (void *cls,
2043 void *rd)
2044{
2045 struct GNUNET_CRYPTO_BlindSignPrivateKey **priv = rd;
2046
2047 (void) cls;
2048 GNUNET_CRYPTO_blind_sign_priv_decref (*priv);
2049 *priv = NULL;
2050}
2051
2052
2053struct GNUNET_PQ_ResultSpec
2054GNUNET_PQ_result_spec_blind_sign_priv (const char *name,
2055 struct GNUNET_CRYPTO_BlindSignPrivateKey **priv)
2056{
2057 struct GNUNET_PQ_ResultSpec res = {
2058 .conv = &extract_blind_sign_priv,
2059 .cleaner = &clean_blind_sign_priv,
2060 .dst = (void *) priv,
2061 .fname = name
2062 };
2063
2064 return res;
2065}
2066
2067/* end of pq_result_helper.c */