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