Merge branch 'master' of git+ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / pq / pq_result_helper.c
1  /*
2   This file is part of GNUnet
3   Copyright (C) 2014, 2015, 2016 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  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_pq_lib.h"
28
29
30 /**
31  * Function called to clean up memory allocated
32  * by a #GNUNET_PQ_ResultConverter.
33  *
34  * @param cls closure
35  * @param rd result data to clean up
36  */
37 static void
38 clean_varsize_blob (void *cls,
39                     void *rd)
40 {
41   void **dst = rd;
42
43   (void) cls;
44   if (NULL != *dst)
45   {
46     GNUNET_free (*dst);
47     *dst = NULL;
48   }
49 }
50
51
52 /**
53  * Extract data from a Postgres database @a result at row @a row.
54  *
55  * @param cls closure
56  * @param result where to extract data from
57  * @param int row to extract data from
58  * @param fname name (or prefix) of the fields to extract from
59  * @param[in,out] dst_size where to store size of result, may be NULL
60  * @param[out] dst where to store the result
61  * @return
62  *   #GNUNET_YES if all results could be extracted
63  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
64  */
65 static int
66 extract_varsize_blob (void *cls,
67                       PGresult *result,
68                       int row,
69                       const char *fname,
70                       size_t *dst_size,
71                       void *dst)
72 {
73   size_t len;
74   const char *res;
75   void *idst;
76   int fnum;
77
78   (void) cls;
79   *dst_size = 0;
80   *((void **) dst) = NULL;
81
82   fnum = PQfnumber (result,
83                     fname);
84   if (fnum < 0)
85   {
86     GNUNET_break (0);
87     return GNUNET_SYSERR;
88   }
89   if (PQgetisnull (result,
90                    row,
91                    fnum))
92   {
93     /* Let's allow this for varsize */
94     return GNUNET_OK;
95   }
96   /* if a field is null, continue but
97    * remember that we now return a different result */
98   len = PQgetlength (result,
99                      row,
100                      fnum);
101   res = PQgetvalue (result,
102                     row,
103                     fnum);
104   GNUNET_assert (NULL != res);
105   *dst_size = len;
106   idst = GNUNET_malloc (len);
107   *((void **) dst) = idst;
108   GNUNET_memcpy (idst,
109                  res,
110                  len);
111   return GNUNET_OK;
112 }
113
114
115 /**
116  * Variable-size result expected.
117  *
118  * @param name name of the field in the table
119  * @param[out] dst where to store the result, allocated
120  * @param[out] sptr where to store the size of @a dst
121  * @return array entry for the result specification to use
122  */
123 struct GNUNET_PQ_ResultSpec
124 GNUNET_PQ_result_spec_variable_size (const char *name,
125                                      void **dst,
126                                      size_t *sptr)
127 {
128   struct GNUNET_PQ_ResultSpec res =
129     { &extract_varsize_blob,
130       &clean_varsize_blob, NULL,
131       (void *) (dst), 0, name, sptr };
132   return res;
133 }
134
135
136 /**
137  * Extract data from a Postgres database @a result at row @a row.
138  *
139  * @param cls closure
140  * @param result where to extract data from
141  * @param int row to extract data from
142  * @param fname name (or prefix) of the fields to extract from
143  * @param[in] dst_size desired size, never NULL
144  * @param[out] dst where to store the result
145  * @return
146  *   #GNUNET_YES if all results could be extracted
147  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
148  */
149 static int
150 extract_fixed_blob (void *cls,
151                     PGresult *result,
152                     int row,
153                     const char *fname,
154                     size_t *dst_size,
155                     void *dst)
156 {
157   size_t len;
158   const char *res;
159   int fnum;
160
161   (void) cls;
162   fnum = PQfnumber (result,
163                     fname);
164   if (fnum < 0)
165   {
166     GNUNET_break (0);
167     return GNUNET_SYSERR;
168   }
169   if (PQgetisnull (result,
170                    row,
171                    fnum))
172   {
173     GNUNET_break (0);
174     return GNUNET_SYSERR;
175   }
176
177   /* if a field is null, continue but
178    * remember that we now return a different result */
179   len = PQgetlength (result,
180                      row,
181                      fnum);
182   if (*dst_size != len)
183   {
184     GNUNET_break (0);
185     return GNUNET_SYSERR;
186   }
187   res = PQgetvalue (result,
188                     row,
189                     fnum);
190   GNUNET_assert (NULL != res);
191   GNUNET_memcpy (dst,
192                  res,
193                  len);
194   return GNUNET_OK;
195 }
196
197
198 /**
199  * Fixed-size result expected.
200  *
201  * @param name name of the field in the table
202  * @param[out] dst where to store the result
203  * @param dst_size number of bytes in @a dst
204  * @return array entry for the result specification to use
205  */
206 struct GNUNET_PQ_ResultSpec
207 GNUNET_PQ_result_spec_fixed_size (const char *name,
208                                   void *dst,
209                                   size_t dst_size)
210 {
211   struct GNUNET_PQ_ResultSpec res =
212     { &extract_fixed_blob,
213       NULL, NULL,
214       (dst), dst_size, name, NULL };
215   return res;
216 }
217
218
219 /**
220  * Extract data from a Postgres database @a result at row @a row.
221  *
222  * @param cls closure
223  * @param result where to extract data from
224  * @param int row to extract data from
225  * @param fname name (or prefix) of the fields to extract from
226  * @param[in,out] dst_size where to store size of result, may be NULL
227  * @param[out] dst where to store the result
228  * @return
229  *   #GNUNET_YES if all results could be extracted
230  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
231  */
232 static int
233 extract_rsa_public_key (void *cls,
234                         PGresult *result,
235                         int row,
236                         const char *fname,
237                         size_t *dst_size,
238                         void *dst)
239 {
240   struct GNUNET_CRYPTO_RsaPublicKey **pk = dst;
241   size_t len;
242   const char *res;
243   int fnum;
244
245   (void) cls;
246   *pk = NULL;
247   fnum = PQfnumber (result,
248                     fname);
249   if (fnum < 0)
250   {
251     GNUNET_break (0);
252     return GNUNET_SYSERR;
253   }
254   if (PQgetisnull (result,
255                    row,
256                    fnum))
257   {
258     GNUNET_break (0);
259     return GNUNET_SYSERR;
260   }
261   /* if a field is null, continue but
262    * remember that we now return a different result */
263   len = PQgetlength (result,
264                      row,
265                      fnum);
266   res = PQgetvalue (result,
267                     row,
268                     fnum);
269   *pk = GNUNET_CRYPTO_rsa_public_key_decode (res,
270                                              len);
271   if (NULL == *pk)
272   {
273     GNUNET_break (0);
274     return GNUNET_SYSERR;
275   }
276   return GNUNET_OK;
277 }
278
279
280 /**
281  * Function called to clean up memory allocated
282  * by a #GNUNET_PQ_ResultConverter.
283  *
284  * @param cls closure
285  * @param rd result data to clean up
286  */
287 static void
288 clean_rsa_public_key (void *cls,
289                       void *rd)
290 {
291   struct GNUNET_CRYPTO_RsaPublicKey **pk = rd;
292
293   (void) cls;
294   if (NULL != *pk)
295   {
296     GNUNET_CRYPTO_rsa_public_key_free (*pk);
297     *pk = NULL;
298   }
299 }
300
301
302 /**
303  * RSA public key expected.
304  *
305  * @param name name of the field in the table
306  * @param[out] rsa where to store the result
307  * @return array entry for the result specification to use
308  */
309 struct GNUNET_PQ_ResultSpec
310 GNUNET_PQ_result_spec_rsa_public_key (const char *name,
311                                       struct GNUNET_CRYPTO_RsaPublicKey **rsa)
312 {
313   struct GNUNET_PQ_ResultSpec res =
314     { &extract_rsa_public_key,
315       &clean_rsa_public_key,
316       NULL,
317       (void *) rsa, 0, name, NULL };
318   return res;
319 }
320
321
322 /**
323  * Extract data from a Postgres database @a result at row @a row.
324  *
325  * @param cls closure
326  * @param result where to extract data from
327  * @param int row to extract data from
328  * @param fname name (or prefix) of the fields to extract from
329  * @param[in,out] dst_size where to store size of result, may be NULL
330  * @param[out] dst where to store the result
331  * @return
332  *   #GNUNET_YES if all results could be extracted
333  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
334  */
335 static int
336 extract_rsa_signature (void *cls,
337                        PGresult *result,
338                        int row,
339                        const char *fname,
340                        size_t *dst_size,
341                        void *dst)
342 {
343   struct GNUNET_CRYPTO_RsaSignature **sig = dst;
344   size_t len;
345   const char *res;
346   int fnum;
347
348   (void) cls;
349   *sig = NULL;
350   fnum = PQfnumber (result,
351                     fname);
352   if (fnum < 0)
353   {
354     GNUNET_break (0);
355     return GNUNET_SYSERR;
356   }
357   if (PQgetisnull (result,
358                    row,
359                    fnum))
360   {
361     GNUNET_break (0);
362     return GNUNET_SYSERR;
363   }
364   /* if a field is null, continue but
365    * remember that we now return a different result */
366   len = PQgetlength (result,
367                      row,
368                      fnum);
369   res = PQgetvalue (result,
370                     row,
371                     fnum);
372   *sig = GNUNET_CRYPTO_rsa_signature_decode (res,
373                                              len);
374   if (NULL == *sig)
375   {
376     GNUNET_break (0);
377     return GNUNET_SYSERR;
378   }
379   return GNUNET_OK;
380 }
381
382
383 /**
384  * Function called to clean up memory allocated
385  * by a #GNUNET_PQ_ResultConverter.
386  *
387  * @param cls closure
388  * @param rd result data to clean up
389  */
390 static void
391 clean_rsa_signature (void *cls,
392                      void *rd)
393 {
394   struct GNUNET_CRYPTO_RsaSignature **sig = rd;
395
396   (void) cls;
397   if (NULL != *sig)
398   {
399     GNUNET_CRYPTO_rsa_signature_free (*sig);
400     *sig = NULL;
401   }
402 }
403
404
405 /**
406  * RSA signature expected.
407  *
408  * @param name name of the field in the table
409  * @param[out] sig where to store the result;
410  * @return array entry for the result specification to use
411  */
412 struct GNUNET_PQ_ResultSpec
413 GNUNET_PQ_result_spec_rsa_signature (const char *name,
414                                     struct GNUNET_CRYPTO_RsaSignature **sig)
415 {
416   struct GNUNET_PQ_ResultSpec res =
417     { &extract_rsa_signature,
418       &clean_rsa_signature,
419       NULL,
420       (void *) sig, 0, (name), NULL };
421   return res;
422 }
423
424
425 /**
426  * Extract data from a Postgres database @a result at row @a row.
427  *
428  * @param cls closure
429  * @param result where to extract data from
430  * @param int row to extract data from
431  * @param fname name (or prefix) of the fields to extract from
432  * @param[in,out] dst_size where to store size of result, may be NULL
433  * @param[out] dst where to store the result
434  * @return
435  *   #GNUNET_YES if all results could be extracted
436  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
437  */
438 static int
439 extract_string (void *cls,
440                 PGresult *result,
441                 int row,
442                 const char *fname,
443                 size_t *dst_size,
444                 void *dst)
445 {
446   char **str = dst;
447   size_t len;
448   const char *res;
449   int fnum;
450
451   (void) cls;
452   *str = NULL;
453   fnum = PQfnumber (result,
454                     fname);
455   if (fnum < 0)
456   {
457     GNUNET_break (0);
458     return GNUNET_SYSERR;
459   }
460   if (PQgetisnull (result,
461                    row,
462                    fnum))
463   {
464     GNUNET_break (0);
465     return GNUNET_SYSERR;
466   }
467   /* if a field is null, continue but
468    * remember that we now return a different result */
469   len = PQgetlength (result,
470                      row,
471                      fnum);
472   res = PQgetvalue (result,
473                     row,
474                     fnum);
475   *str = GNUNET_strndup (res,
476                          len);
477   if (NULL == *str)
478   {
479     GNUNET_break (0);
480     return GNUNET_SYSERR;
481   }
482   return GNUNET_OK;
483 }
484
485
486 /**
487  * Function called to clean up memory allocated
488  * by a #GNUNET_PQ_ResultConverter.
489  *
490  * @param cls closure
491  * @param rd result data to clean up
492  */
493 static void
494 clean_string (void *cls,
495               void *rd)
496 {
497   char **str = rd;
498
499   (void) cls;
500   if (NULL != *str)
501   {
502     GNUNET_free (*str);
503     *str = NULL;
504   }
505 }
506
507
508 /**
509  * 0-terminated string expected.
510  *
511  * @param name name of the field in the table
512  * @param[out] dst where to store the result, allocated
513  * @return array entry for the result specification to use
514  */
515 struct GNUNET_PQ_ResultSpec
516 GNUNET_PQ_result_spec_string (const char *name,
517                               char **dst)
518 {
519   struct GNUNET_PQ_ResultSpec res =
520     { &extract_string,
521       &clean_string,
522       NULL,
523       (void *) dst, 0, (name), NULL };
524   return res;
525 }
526
527
528 /**
529  * Extract data from a Postgres database @a result at row @a row.
530  *
531  * @param cls closure
532  * @param result where to extract data from
533  * @param int row to extract data from
534  * @param fname name (or prefix) of the fields to extract from
535  * @param[in,out] dst_size where to store size of result, may be NULL
536  * @param[out] dst where to store the result
537  * @return
538  *   #GNUNET_YES if all results could be extracted
539  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
540  */
541 static int
542 extract_abs_time (void *cls,
543                   PGresult *result,
544                   int row,
545                   const char *fname,
546                   size_t *dst_size,
547                   void *dst)
548 {
549   struct GNUNET_TIME_Absolute *udst = dst;
550   const int64_t *res;
551   int fnum;
552
553   (void) cls;
554   fnum = PQfnumber (result,
555                     fname);
556   if (fnum < 0)
557   {
558     GNUNET_break (0);
559     return GNUNET_SYSERR;
560   }
561   if (PQgetisnull (result,
562                    row,
563                    fnum))
564   {
565     GNUNET_break (0);
566     return GNUNET_SYSERR;
567   }
568   GNUNET_assert (NULL != dst);
569   if (sizeof (struct GNUNET_TIME_Absolute) != *dst_size)
570   {
571     GNUNET_break (0);
572     return GNUNET_SYSERR;
573   }
574   if (sizeof (int64_t) !=
575       PQgetlength (result,
576                    row,
577                    fnum))
578   {
579     GNUNET_break (0);
580     return GNUNET_SYSERR;
581   }
582   res = (int64_t *) PQgetvalue (result,
583                                 row,
584                                 fnum);
585   if (INT64_MAX == *res)
586     *udst = GNUNET_TIME_UNIT_FOREVER_ABS;
587   else
588     udst->abs_value_us = GNUNET_ntohll ((uint64_t) *res);
589   return GNUNET_OK;
590 }
591
592
593 /**
594  * Absolute time expected.
595  *
596  * @param name name of the field in the table
597  * @param[out] at where to store the result
598  * @return array entry for the result specification to use
599  */
600 struct GNUNET_PQ_ResultSpec
601 GNUNET_PQ_result_spec_absolute_time (const char *name,
602                                      struct GNUNET_TIME_Absolute *at)
603 {
604   struct GNUNET_PQ_ResultSpec res =
605     { &extract_abs_time,
606       NULL,
607       NULL,
608       (void *) at, sizeof (*at), (name), NULL };
609   return res;
610 }
611
612
613 /**
614  * Absolute time in network byte order expected.
615  *
616  * @param name name of the field in the table
617  * @param[out] at where to store the result
618  * @return array entry for the result specification to use
619  */
620 struct GNUNET_PQ_ResultSpec
621 GNUNET_PQ_result_spec_absolute_time_nbo (const char *name,
622                                          struct GNUNET_TIME_AbsoluteNBO *at)
623 {
624   struct GNUNET_PQ_ResultSpec res =
625     GNUNET_PQ_result_spec_auto_from_type(name, &at->abs_value_us__);
626   return res;
627 }
628
629
630 /**
631  * Extract data from a Postgres database @a result at row @a row.
632  *
633  * @param cls closure
634  * @param result where to extract data from
635  * @param int row to extract data from
636  * @param fname name (or prefix) of the fields to extract from
637  * @param[in,out] dst_size where to store size of result, may be NULL
638  * @param[out] dst where to store the result
639  * @return
640  *   #GNUNET_YES if all results could be extracted
641  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
642  */
643 static int
644 extract_uint16 (void *cls,
645                 PGresult *result,
646                 int row,
647                 const char *fname,
648                 size_t *dst_size,
649                 void *dst)
650 {
651   uint16_t *udst = dst;
652   const uint16_t *res;
653   int fnum;
654
655   (void) cls;
656   fnum = PQfnumber (result,
657                     fname);
658   if (fnum < 0)
659   {
660     GNUNET_break (0);
661     return GNUNET_SYSERR;
662   }
663   if (PQgetisnull (result,
664                    row,
665                    fnum))
666   {
667     GNUNET_break (0);
668     return GNUNET_SYSERR;
669   }
670   GNUNET_assert (NULL != dst);
671   if (sizeof (uint16_t) != *dst_size)
672   {
673     GNUNET_break (0);
674     return GNUNET_SYSERR;
675   }
676   if (sizeof (uint16_t) !=
677       PQgetlength (result,
678                    row,
679                    fnum))
680   {
681     GNUNET_break (0);
682     return GNUNET_SYSERR;
683   }
684   res = (uint16_t *) PQgetvalue (result,
685                                  row,
686                                  fnum);
687   *udst = ntohs (*res);
688   return GNUNET_OK;
689 }
690
691
692 /**
693  * uint16_t expected.
694  *
695  * @param name name of the field in the table
696  * @param[out] u16 where to store the result
697  * @return array entry for the result specification to use
698  */
699 struct GNUNET_PQ_ResultSpec
700 GNUNET_PQ_result_spec_uint16 (const char *name,
701                               uint16_t *u16)
702 {
703   struct GNUNET_PQ_ResultSpec res =
704     { &extract_uint16,
705       NULL,
706       NULL,
707       (void *) u16, sizeof (*u16), (name), NULL };
708   return res;
709 }
710
711
712 /**
713  * Extract data from a Postgres database @a result at row @a row.
714  *
715  * @param cls closure
716  * @param result where to extract data from
717  * @param int row to extract data from
718  * @param fname name (or prefix) of the fields to extract from
719  * @param[in,out] dst_size where to store size of result, may be NULL
720  * @param[out] dst where to store the result
721  * @return
722  *   #GNUNET_YES if all results could be extracted
723  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
724  */
725 static int
726 extract_uint32 (void *cls,
727                 PGresult *result,
728                 int row,
729                 const char *fname,
730                 size_t *dst_size,
731                 void *dst)
732 {
733   uint32_t *udst = dst;
734   const uint32_t *res;
735   int fnum;
736
737   (void) cls;
738   fnum = PQfnumber (result,
739                     fname);
740   if (fnum < 0)
741   {
742     GNUNET_break (0);
743     return GNUNET_SYSERR;
744   }
745   if (PQgetisnull (result,
746                    row,
747                    fnum))
748   {
749     GNUNET_break (0);
750     return GNUNET_SYSERR;
751   }
752   GNUNET_assert (NULL != dst);
753   if (sizeof (uint32_t) != *dst_size)
754   {
755     GNUNET_break (0);
756     return GNUNET_SYSERR;
757   }
758   if (sizeof (uint32_t) !=
759       PQgetlength (result,
760                    row,
761                    fnum))
762   {
763     GNUNET_break (0);
764     return GNUNET_SYSERR;
765   }
766   res = (uint32_t *) PQgetvalue (result,
767                                  row,
768                                  fnum);
769   *udst = ntohl (*res);
770   return GNUNET_OK;
771 }
772
773
774 /**
775  * uint32_t expected.
776  *
777  * @param name name of the field in the table
778  * @param[out] u32 where to store the result
779  * @return array entry for the result specification to use
780  */
781 struct GNUNET_PQ_ResultSpec
782 GNUNET_PQ_result_spec_uint32 (const char *name,
783                               uint32_t *u32)
784 {
785   struct GNUNET_PQ_ResultSpec res =
786     { &extract_uint32,
787       NULL,
788       NULL,
789       (void *) u32, sizeof (*u32), (name), NULL };
790   return res;
791 }
792
793
794 /**
795  * Extract data from a Postgres database @a result at row @a row.
796  *
797  * @param cls closure
798  * @param result where to extract data from
799  * @param int row to extract data from
800  * @param fname name (or prefix) of the fields to extract from
801  * @param[in,out] dst_size where to store size of result, may be NULL
802  * @param[out] dst where to store the result
803  * @return
804  *   #GNUNET_YES if all results could be extracted
805  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
806  */
807 static int
808 extract_uint64 (void *cls,
809                 PGresult *result,
810                 int row,
811                 const char *fname,
812                 size_t *dst_size,
813                 void *dst)
814 {
815   uint64_t *udst = dst;
816   const uint64_t *res;
817   int fnum;
818
819   (void) cls;
820   fnum = PQfnumber (result,
821                     fname);
822   if (fnum < 0)
823   {
824     GNUNET_break (0);
825     return GNUNET_SYSERR;
826   }
827   if (PQgetisnull (result,
828                    row,
829                    fnum))
830   {
831     GNUNET_break (0);
832     return GNUNET_SYSERR;
833   }
834   GNUNET_assert (NULL != dst);
835   if (sizeof (uint64_t) != *dst_size)
836   {
837     GNUNET_break (0);
838     return GNUNET_SYSERR;
839   }
840   if (sizeof (uint64_t) !=
841       PQgetlength (result,
842                    row,
843                    fnum))
844   {
845     GNUNET_break (0);
846     return GNUNET_SYSERR;
847   }
848   res = (uint64_t *) PQgetvalue (result,
849                                  row,
850                                  fnum);
851   *udst = GNUNET_ntohll (*res);
852   return GNUNET_OK;
853 }
854
855
856 /**
857  * uint64_t expected.
858  *
859  * @param name name of the field in the table
860  * @param[out] u64 where to store the result
861  * @return array entry for the result specification to use
862  */
863 struct GNUNET_PQ_ResultSpec
864 GNUNET_PQ_result_spec_uint64 (const char *name,
865                               uint64_t *u64)
866 {
867   struct GNUNET_PQ_ResultSpec res =
868     { &extract_uint64,
869       NULL,
870       NULL,
871       (void *) u64, sizeof (*u64), (name), NULL };
872   return res;
873 }
874
875
876 /* end of pq_result_helper.c */