bitch more if NULL rows cause PQ result extraction to fail
[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   *dst_size = 0;
74   *((void **) dst) = NULL;
75
76   fnum = PQfnumber (result,
77                     fname);
78   if (fnum < 0)
79   {
80     GNUNET_break (0);
81     return GNUNET_SYSERR;
82   }
83   if (PQgetisnull (result,
84                    row,
85                    fnum))
86   {
87     GNUNET_break (0);
88     return GNUNET_SYSERR;
89   }
90   /* if a field is null, continue but
91    * remember that we now return a different result */
92   len = PQgetlength (result,
93                      row,
94                      fnum);
95   res = PQgetvalue (result,
96                     row,
97                     fnum);
98   GNUNET_assert (NULL != res);
99   *dst_size = len;
100   idst = GNUNET_malloc (len);
101   *((void **) dst) = idst;
102   GNUNET_memcpy (idst,
103           res,
104           len);
105   return GNUNET_OK;
106 }
107
108
109 /**
110  * Variable-size result expected.
111  *
112  * @param name name of the field in the table
113  * @param[out] dst where to store the result, allocated
114  * @param[out] sptr where to store the size of @a dst
115  * @return array entry for the result specification to use
116  */
117 struct GNUNET_PQ_ResultSpec
118 GNUNET_PQ_result_spec_variable_size (const char *name,
119                                      void **dst,
120                                      size_t *sptr)
121 {
122   struct GNUNET_PQ_ResultSpec res =
123     { &extract_varsize_blob,
124       &clean_varsize_blob, NULL,
125       (void *) (dst), 0, name, sptr };
126   return res;
127 }
128
129
130 /**
131  * Extract data from a Postgres database @a result at row @a row.
132  *
133  * @param cls closure
134  * @param result where to extract data from
135  * @param int row to extract data from
136  * @param fname name (or prefix) of the fields to extract from
137  * @param[in] dst_size desired size, never NULL
138  * @param[out] dst where to store the result
139  * @return
140  *   #GNUNET_YES if all results could be extracted
141  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
142  */
143 static int
144 extract_fixed_blob (void *cls,
145                     PGresult *result,
146                     int row,
147                     const char *fname,
148                     size_t *dst_size,
149                     void *dst)
150 {
151   size_t len;
152   const char *res;
153   int fnum;
154
155   fnum = PQfnumber (result,
156                     fname);
157   if (fnum < 0)
158   {
159     GNUNET_break (0);
160     return GNUNET_SYSERR;
161   }
162   if (PQgetisnull (result,
163                    row,
164                    fnum))
165   {
166     GNUNET_break (0);
167     return GNUNET_SYSERR;
168   } 
169
170   /* if a field is null, continue but
171    * remember that we now return a different result */
172   len = PQgetlength (result,
173                      row,
174                      fnum);
175   if (*dst_size != len)
176   {
177     GNUNET_break (0);
178     return GNUNET_SYSERR;
179   }
180   res = PQgetvalue (result,
181                     row,
182                     fnum);
183   GNUNET_assert (NULL != res);
184   GNUNET_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_break (0);
244     return GNUNET_SYSERR;
245   }
246   if (PQgetisnull (result,
247                    row,
248                    fnum))
249   {
250     GNUNET_break (0);
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_break (0);
266     return GNUNET_SYSERR;
267   }
268   return GNUNET_OK;
269 }
270
271
272 /**
273  * Function called to clean up memory allocated
274  * by a #GNUNET_PQ_ResultConverter.
275  *
276  * @param cls closure
277  * @param rd result data to clean up
278  */
279 static void
280 clean_rsa_public_key (void *cls,
281                       void *rd)
282 {
283   struct GNUNET_CRYPTO_RsaPublicKey **pk = rd;
284
285   if (NULL != *pk)
286   {
287     GNUNET_CRYPTO_rsa_public_key_free (*pk);
288     *pk = NULL;
289   }
290 }
291
292
293 /**
294  * RSA public key expected.
295  *
296  * @param name name of the field in the table
297  * @param[out] rsa where to store the result
298  * @return array entry for the result specification to use
299  */
300 struct GNUNET_PQ_ResultSpec
301 GNUNET_PQ_result_spec_rsa_public_key (const char *name,
302                                       struct GNUNET_CRYPTO_RsaPublicKey **rsa)
303 {
304   struct GNUNET_PQ_ResultSpec res =
305     { &extract_rsa_public_key,
306       &clean_rsa_public_key,
307       NULL,
308       (void *) rsa, 0, name, NULL };
309   return res;
310 }
311
312
313 /**
314  * Extract data from a Postgres database @a result at row @a row.
315  *
316  * @param cls closure
317  * @param result where to extract data from
318  * @param int row to extract data from
319  * @param fname name (or prefix) of the fields to extract from
320  * @param[in,out] dst_size where to store size of result, may be NULL
321  * @param[out] dst where to store the result
322  * @return
323  *   #GNUNET_YES if all results could be extracted
324  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
325  */
326 static int
327 extract_rsa_signature (void *cls,
328                        PGresult *result,
329                        int row,
330                        const char *fname,
331                        size_t *dst_size,
332                        void *dst)
333 {
334   struct GNUNET_CRYPTO_RsaSignature **sig = dst;
335   size_t len;
336   const char *res;
337   int fnum;
338
339   *sig = NULL;
340   fnum = PQfnumber (result,
341                     fname);
342   if (fnum < 0)
343   {
344     GNUNET_break (0);
345     return GNUNET_SYSERR;
346   }
347   if (PQgetisnull (result,
348                    row,
349                    fnum))
350   {
351     GNUNET_break (0);
352     return GNUNET_SYSERR;
353   }
354   /* if a field is null, continue but
355    * remember that we now return a different result */
356   len = PQgetlength (result,
357                      row,
358                      fnum);
359   res = PQgetvalue (result,
360                     row,
361                     fnum);
362   *sig = GNUNET_CRYPTO_rsa_signature_decode (res,
363                                              len);
364   if (NULL == *sig)
365   {
366     GNUNET_break (0);
367     return GNUNET_SYSERR;
368   }
369   return GNUNET_OK;
370 }
371
372
373 /**
374  * Function called to clean up memory allocated
375  * by a #GNUNET_PQ_ResultConverter.
376  *
377  * @param cls closure
378  * @param rd result data to clean up
379  */
380 static void
381 clean_rsa_signature (void *cls,
382                      void *rd)
383 {
384   struct GNUNET_CRYPTO_RsaSignature **sig = rd;
385
386   if (NULL != *sig)
387   {
388     GNUNET_CRYPTO_rsa_signature_free (*sig);
389     *sig = NULL;
390   }
391 }
392
393
394 /**
395  * RSA signature expected.
396  *
397  * @param name name of the field in the table
398  * @param[out] sig where to store the result;
399  * @return array entry for the result specification to use
400  */
401 struct GNUNET_PQ_ResultSpec
402 GNUNET_PQ_result_spec_rsa_signature (const char *name,
403                                     struct GNUNET_CRYPTO_RsaSignature **sig)
404 {
405   struct GNUNET_PQ_ResultSpec res =
406     { &extract_rsa_signature,
407       &clean_rsa_signature,
408       NULL,
409       (void *) sig, 0, (name), NULL };
410   return res;
411 }
412
413
414 /**
415  * Extract data from a Postgres database @a result at row @a row.
416  *
417  * @param cls closure
418  * @param result where to extract data from
419  * @param int row to extract data from
420  * @param fname name (or prefix) of the fields to extract from
421  * @param[in,out] dst_size where to store size of result, may be NULL
422  * @param[out] dst where to store the result
423  * @return
424  *   #GNUNET_YES if all results could be extracted
425  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
426  */
427 static int
428 extract_string (void *cls,
429                 PGresult *result,
430                 int row,
431                 const char *fname,
432                 size_t *dst_size,
433                 void *dst)
434 {
435   char **str = dst;
436   size_t len;
437   const char *res;
438   int fnum;
439
440   *str = NULL;
441   fnum = PQfnumber (result,
442                     fname);
443   if (fnum < 0)
444   {
445     GNUNET_break (0);
446     return GNUNET_SYSERR;
447   }
448   if (PQgetisnull (result,
449                    row,
450                    fnum))
451   {
452     GNUNET_break (0);
453     return GNUNET_SYSERR;
454   }
455   /* if a field is null, continue but
456    * remember that we now return a different result */
457   len = PQgetlength (result,
458                      row,
459                      fnum);
460   res = PQgetvalue (result,
461                     row,
462                     fnum);
463   *str = GNUNET_strndup (res,
464                          len);
465   if (NULL == *str)
466   {
467     GNUNET_break (0);
468     return GNUNET_SYSERR;
469   }
470   return GNUNET_OK;
471 }
472
473
474 /**
475  * Function called to clean up memory allocated
476  * by a #GNUNET_PQ_ResultConverter.
477  *
478  * @param cls closure
479  * @param rd result data to clean up
480  */
481 static void
482 clean_string (void *cls,
483               void *rd)
484 {
485   char **str = rd;
486
487   if (NULL != *str)
488   {
489     GNUNET_free (*str);
490     *str = NULL;
491   }
492 }
493
494
495 /**
496  * 0-terminated string expected.
497  *
498  * @param name name of the field in the table
499  * @param[out] dst where to store the result, allocated
500  * @return array entry for the result specification to use
501  */
502 struct GNUNET_PQ_ResultSpec
503 GNUNET_PQ_result_spec_string (const char *name,
504                               char **dst)
505 {
506   struct GNUNET_PQ_ResultSpec res =
507     { &extract_string,
508       &clean_string,
509       NULL,
510       (void *) dst, 0, (name), NULL };
511   return res;
512 }
513
514
515 /**
516  * Absolute time expected.
517  *
518  * @param name name of the field in the table
519  * @param[out] at where to store the result
520  * @return array entry for the result specification to use
521  */
522 struct GNUNET_PQ_ResultSpec
523 GNUNET_PQ_result_spec_absolute_time (const char *name,
524                                      struct GNUNET_TIME_Absolute *at)
525 {
526   return GNUNET_PQ_result_spec_uint64 (name,
527                                        &at->abs_value_us);
528 }
529
530
531 /**
532  * Absolute time in network byte order expected.
533  *
534  * @param name name of the field in the table
535  * @param[out] at where to store the result
536  * @return array entry for the result specification to use
537  */
538 struct GNUNET_PQ_ResultSpec
539 GNUNET_PQ_result_spec_absolute_time_nbo (const char *name,
540                                          struct GNUNET_TIME_AbsoluteNBO *at)
541 {
542   struct GNUNET_PQ_ResultSpec res =
543     GNUNET_PQ_result_spec_auto_from_type(name, &at->abs_value_us__);
544   return res;
545 }
546
547
548 /**
549  * Extract data from a Postgres database @a result at row @a row.
550  *
551  * @param cls closure
552  * @param result where to extract data from
553  * @param int row to extract data from
554  * @param fname name (or prefix) of the fields to extract from
555  * @param[in,out] dst_size where to store size of result, may be NULL
556  * @param[out] dst where to store the result
557  * @return
558  *   #GNUNET_YES if all results could be extracted
559  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
560  */
561 static int
562 extract_uint16 (void *cls,
563                 PGresult *result,
564                 int row,
565                 const char *fname,
566                 size_t *dst_size,
567                 void *dst)
568 {
569   uint16_t *udst = dst;
570   const uint16_t *res;
571   int fnum;
572
573   fnum = PQfnumber (result,
574                     fname);
575   if (fnum < 0)
576   {
577     GNUNET_break (0);
578     return GNUNET_SYSERR;
579   }
580   if (PQgetisnull (result,
581                    row,
582                    fnum))
583   { 
584     GNUNET_break (0);
585     return GNUNET_SYSERR;
586   }
587   GNUNET_assert (NULL != dst);
588   if (sizeof (uint16_t) != *dst_size)
589   {
590     GNUNET_break (0);
591     return GNUNET_SYSERR;
592   }
593   res = (uint16_t *) PQgetvalue (result,
594                                  row,
595                                  fnum);
596   *udst = ntohs (*res);
597   return GNUNET_OK;
598 }
599
600
601 /**
602  * uint16_t expected.
603  *
604  * @param name name of the field in the table
605  * @param[out] u16 where to store the result
606  * @return array entry for the result specification to use
607  */
608 struct GNUNET_PQ_ResultSpec
609 GNUNET_PQ_result_spec_uint16 (const char *name,
610                               uint16_t *u16)
611 {
612   struct GNUNET_PQ_ResultSpec res =
613     { &extract_uint16,
614       NULL,
615       NULL,
616       (void *) u16, sizeof (*u16), (name), NULL };
617   return res;
618 }
619
620
621 /**
622  * Extract data from a Postgres database @a result at row @a row.
623  *
624  * @param cls closure
625  * @param result where to extract data from
626  * @param int row to extract data from
627  * @param fname name (or prefix) of the fields to extract from
628  * @param[in,out] dst_size where to store size of result, may be NULL
629  * @param[out] dst where to store the result
630  * @return
631  *   #GNUNET_YES if all results could be extracted
632  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
633  */
634 static int
635 extract_uint32 (void *cls,
636                 PGresult *result,
637                 int row,
638                 const char *fname,
639                 size_t *dst_size,
640                 void *dst)
641 {
642   uint32_t *udst = dst;
643   const uint32_t *res;
644   int fnum;
645
646   fnum = PQfnumber (result,
647                     fname);
648   if (fnum < 0)
649   {
650     GNUNET_break (0);
651     return GNUNET_SYSERR;
652   }
653   if (PQgetisnull (result,
654                    row,
655                    fnum))
656   {
657     GNUNET_break (0);
658     return GNUNET_SYSERR;
659   }
660   GNUNET_assert (NULL != dst);
661   if (sizeof (uint32_t) != *dst_size)
662   {
663     GNUNET_break (0);
664     return GNUNET_SYSERR;
665   }
666   res = (uint32_t *) PQgetvalue (result,
667                                  row,
668                                  fnum);
669   *udst = ntohl (*res);
670   return GNUNET_OK;
671 }
672
673
674 /**
675  * uint32_t expected.
676  *
677  * @param name name of the field in the table
678  * @param[out] u32 where to store the result
679  * @return array entry for the result specification to use
680  */
681 struct GNUNET_PQ_ResultSpec
682 GNUNET_PQ_result_spec_uint32 (const char *name,
683                               uint32_t *u32)
684 {
685   struct GNUNET_PQ_ResultSpec res =
686     { &extract_uint32,
687       NULL,
688       NULL,
689       (void *) u32, sizeof (*u32), (name), NULL };
690   return res;
691 }
692
693
694 /**
695  * Extract data from a Postgres database @a result at row @a row.
696  *
697  * @param cls closure
698  * @param result where to extract data from
699  * @param int row to extract data from
700  * @param fname name (or prefix) of the fields to extract from
701  * @param[in,out] dst_size where to store size of result, may be NULL
702  * @param[out] dst where to store the result
703  * @return
704  *   #GNUNET_YES if all results could be extracted
705  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
706  */
707 static int
708 extract_uint64 (void *cls,
709                 PGresult *result,
710                 int row,
711                 const char *fname,
712                 size_t *dst_size,
713                 void *dst)
714 {
715   uint64_t *udst = dst;
716   const uint64_t *res;
717   int fnum;
718
719   fnum = PQfnumber (result,
720                     fname);
721   if (fnum < 0)
722   {
723     GNUNET_break (0);
724     return GNUNET_SYSERR;
725   }
726   if (PQgetisnull (result,
727                    row,
728                    fnum))
729   {
730     GNUNET_break (0);
731     return GNUNET_SYSERR;
732   }
733   GNUNET_assert (NULL != dst);
734   if (sizeof (uint64_t) != *dst_size)
735   {
736     GNUNET_break (0);
737     return GNUNET_SYSERR;
738   }
739   res = (uint64_t *) PQgetvalue (result,
740                                  row,
741                                  fnum);
742   *udst = GNUNET_ntohll (*res);
743   return GNUNET_OK;
744 }
745
746
747 /**
748  * uint64_t expected.
749  *
750  * @param name name of the field in the table
751  * @param[out] u64 where to store the result
752  * @return array entry for the result specification to use
753  */
754 struct GNUNET_PQ_ResultSpec
755 GNUNET_PQ_result_spec_uint64 (const char *name,
756                               uint64_t *u64)
757 {
758   struct GNUNET_PQ_ResultSpec res =
759     { &extract_uint64,
760       NULL,
761       NULL,
762       (void *) u64, sizeof (*u64), (name), NULL };
763   return res;
764 }
765
766
767 /* end of pq_result_helper.c */