avoid failing hard if 'gnunetcheck' db does not exist
[oweals/gnunet.git] / src / pq / pq_result_helper.c
index 8baf0b00f30fce87eef05e18f494c3711d07f99a..336ca8c4253556f8de7a2389ab8a72f4eb76724a 100644 (file)
@@ -2,16 +2,20 @@
   This file is part of GNUnet
   Copyright (C) 2014, 2015, 2016 GNUnet e.V.
 
-  GNUnet is free software; you can redistribute it and/or modify it under the
-  terms of the GNU General Public License as published by the Free Software
-  Foundation; either version 3, or (at your option) any later version.
+  GNUnet is free software: you can redistribute it and/or modify it
+  under the terms of the GNU Affero General Public License as published
+  by the Free Software Foundation, either version 3 of the License,
+  or (at your option) any later version.
 
-  GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
-  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Affero General Public License for more details.
 
-  You should have received a copy of the GNU General Public License along with
-  GNUnet; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/>
+  You should have received a copy of the GNU Affero General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
 */
 /**
  * @file pq/pq_result_helper.c
@@ -36,6 +40,7 @@ clean_varsize_blob (void *cls,
 {
   void **dst = rd;
 
+  (void) cls;
   if (NULL != *dst)
   {
     GNUNET_free (*dst);
@@ -55,9 +60,8 @@ clean_varsize_blob (void *cls,
  * @param[out] dst where to store the result
  * @return
  *   #GNUNET_YES if all results could be extracted
- *   #GNUNET_NO if at least one result was NULL
  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
- */ 
+ */
 static int
 extract_varsize_blob (void *cls,
                      PGresult *result,
@@ -70,21 +74,25 @@ extract_varsize_blob (void *cls,
   const char *res;
   void *idst;
   int fnum;
-  
+
+  (void) cls;
+  *dst_size = 0;
+  *((void **) dst) = NULL;
+
   fnum = PQfnumber (result,
                    fname);
   if (fnum < 0)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Field `%s' does not exist in result\n",
-               fname);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   if (PQgetisnull (result,
                   row,
                   fnum))
-    return GNUNET_NO;
-  
+  {
+    /* Let's allow this for varsize */
+    return GNUNET_OK;
+  }
   /* if a field is null, continue but
    * remember that we now return a different result */
   len = PQgetlength (result,
@@ -97,9 +105,9 @@ extract_varsize_blob (void *cls,
   *dst_size = len;
   idst = GNUNET_malloc (len);
   *((void **) dst) = idst;
-  memcpy (idst,
-         res,
-         len);
+  GNUNET_memcpy (idst,
+                 res,
+                 len);
   return GNUNET_OK;
 }
 
@@ -119,7 +127,7 @@ GNUNET_PQ_result_spec_variable_size (const char *name,
 {
   struct GNUNET_PQ_ResultSpec res =
     { &extract_varsize_blob,
-      &clean_varsize_blob, NULL, 
+      &clean_varsize_blob, NULL,
       (void *) (dst), 0, name, sptr };
   return res;
 }
@@ -136,9 +144,8 @@ GNUNET_PQ_result_spec_variable_size (const char *name,
  * @param[out] dst where to store the result
  * @return
  *   #GNUNET_YES if all results could be extracted
- *   #GNUNET_NO if at least one result was NULL
- *   #GNUNET_SYSERR if a result was invalid (non-existing field)
- */ 
+ *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
 static int
 extract_fixed_blob (void *cls,
                    PGresult *result,
@@ -150,42 +157,40 @@ extract_fixed_blob (void *cls,
   size_t len;
   const char *res;
   int fnum;
-  
+
+  (void) cls;
   fnum = PQfnumber (result,
                    fname);
   if (fnum < 0)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Field `%s' does not exist in result\n",
-               fname);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   if (PQgetisnull (result,
                   row,
                   fnum))
-    return GNUNET_NO;
-  
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
   /* if a field is null, continue but
    * remember that we now return a different result */
   len = PQgetlength (result,
                     row,
                     fnum);
-  if (*dst_size != len) 
+  if (*dst_size != len)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Field `%s' has wrong size (got %u, expected %u)\n",
-               fname,
-               (unsigned int) len,
-               (unsigned int) *dst_size);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   res = PQgetvalue (result,
                    row,
                    fnum);
   GNUNET_assert (NULL != res);
-  memcpy (dst,
-         res,
-         len);
+  GNUNET_memcpy (dst,
+                 res,
+                 len);
   return GNUNET_OK;
 }
 
@@ -205,7 +210,7 @@ GNUNET_PQ_result_spec_fixed_size (const char *name,
 {
   struct GNUNET_PQ_ResultSpec res =
     { &extract_fixed_blob,
-      NULL, NULL, 
+      NULL, NULL,
       (dst), dst_size, name, NULL };
   return res;
 }
@@ -222,9 +227,8 @@ GNUNET_PQ_result_spec_fixed_size (const char *name,
  * @param[out] dst where to store the result
  * @return
  *   #GNUNET_YES if all results could be extracted
- *   #GNUNET_NO if at least one result was NULL
- *   #GNUNET_SYSERR if a result was invalid (non-existing field)
- */ 
+ *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
 static int
 extract_rsa_public_key (void *cls,
                        PGresult *result,
@@ -238,21 +242,22 @@ extract_rsa_public_key (void *cls,
   const char *res;
   int fnum;
 
+  (void) cls;
   *pk = NULL;
   fnum = PQfnumber (result,
                    fname);
   if (fnum < 0)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Field `%s' does not exist in result\n",
-               fname);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   if (PQgetisnull (result,
                   row,
                   fnum))
-    return GNUNET_NO;
-
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
   /* if a field is null, continue but
    * remember that we now return a different result */
   len = PQgetlength (result,
@@ -265,9 +270,7 @@ extract_rsa_public_key (void *cls,
                                             len);
   if (NULL == *pk)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Field `%s' contains bogus value (fails to decode)\n",
-               fname);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
@@ -286,7 +289,8 @@ clean_rsa_public_key (void *cls,
                      void *rd)
 {
   struct GNUNET_CRYPTO_RsaPublicKey **pk = rd;
-  
+
+  (void) cls;
   if (NULL != *pk)
   {
     GNUNET_CRYPTO_rsa_public_key_free (*pk);
@@ -326,9 +330,8 @@ GNUNET_PQ_result_spec_rsa_public_key (const char *name,
  * @param[out] dst where to store the result
  * @return
  *   #GNUNET_YES if all results could be extracted
- *   #GNUNET_NO if at least one result was NULL
- *   #GNUNET_SYSERR if a result was invalid (non-existing field)
- */ 
+ *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
 static int
 extract_rsa_signature (void *cls,
                       PGresult *result,
@@ -341,22 +344,23 @@ extract_rsa_signature (void *cls,
   size_t len;
   const char *res;
   int fnum;
-  
+
+  (void) cls;
   *sig = NULL;
   fnum = PQfnumber (result,
                    fname);
   if (fnum < 0)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Field `%s' does not exist in result\n",
-               fname);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   if (PQgetisnull (result,
                   row,
                   fnum))
-    return GNUNET_NO;
-
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
   /* if a field is null, continue but
    * remember that we now return a different result */
   len = PQgetlength (result,
@@ -369,9 +373,7 @@ extract_rsa_signature (void *cls,
                                             len);
   if (NULL == *sig)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Field `%s' contains bogus value (fails to decode)\n",
-               fname);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
@@ -391,6 +393,7 @@ clean_rsa_signature (void *cls,
 {
   struct GNUNET_CRYPTO_RsaSignature **sig = rd;
 
+  (void) cls;
   if (NULL != *sig)
   {
     GNUNET_CRYPTO_rsa_signature_free (*sig);
@@ -419,6 +422,174 @@ GNUNET_PQ_result_spec_rsa_signature (const char *name,
 }
 
 
+/**
+ * Extract data from a Postgres database @a result at row @a row.
+ *
+ * @param cls closure
+ * @param result where to extract data from
+ * @param int row to extract data from
+ * @param fname name (or prefix) of the fields to extract from
+ * @param[in,out] dst_size where to store size of result, may be NULL
+ * @param[out] dst where to store the result
+ * @return
+ *   #GNUNET_YES if all results could be extracted
+ *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
+static int
+extract_string (void *cls,
+                PGresult *result,
+                int row,
+                const char *fname,
+                size_t *dst_size,
+                void *dst)
+{
+  char **str = dst;
+  size_t len;
+  const char *res;
+  int fnum;
+
+  (void) cls;
+  *str = NULL;
+  fnum = PQfnumber (result,
+                   fname);
+  if (fnum < 0)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (PQgetisnull (result,
+                  row,
+                  fnum))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  /* if a field is null, continue but
+   * remember that we now return a different result */
+  len = PQgetlength (result,
+                    row,
+                    fnum);
+  res = PQgetvalue (result,
+                   row,
+                   fnum);
+  *str = GNUNET_strndup (res,
+                         len);
+  if (NULL == *str)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Function called to clean up memory allocated
+ * by a #GNUNET_PQ_ResultConverter.
+ *
+ * @param cls closure
+ * @param rd result data to clean up
+ */
+static void
+clean_string (void *cls,
+              void *rd)
+{
+  char **str = rd;
+
+  (void) cls;
+  if (NULL != *str)
+  {
+    GNUNET_free (*str);
+    *str = NULL;
+  }
+}
+
+
+/**
+ * 0-terminated string expected.
+ *
+ * @param name name of the field in the table
+ * @param[out] dst where to store the result, allocated
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+GNUNET_PQ_result_spec_string (const char *name,
+                              char **dst)
+{
+  struct GNUNET_PQ_ResultSpec res =
+    { &extract_string,
+      &clean_string,
+      NULL,
+      (void *) dst, 0, (name), NULL };
+  return res;
+}
+
+
+/**
+ * Extract data from a Postgres database @a result at row @a row.
+ *
+ * @param cls closure
+ * @param result where to extract data from
+ * @param int row to extract data from
+ * @param fname name (or prefix) of the fields to extract from
+ * @param[in,out] dst_size where to store size of result, may be NULL
+ * @param[out] dst where to store the result
+ * @return
+ *   #GNUNET_YES if all results could be extracted
+ *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
+static int
+extract_abs_time (void *cls,
+                 PGresult *result,
+                 int row,
+                 const char *fname,
+                 size_t *dst_size,
+                 void *dst)
+{
+  struct GNUNET_TIME_Absolute *udst = dst;
+  const int64_t *res;
+  int fnum;
+
+  (void) cls;
+  fnum = PQfnumber (result,
+                   fname);
+  if (fnum < 0)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (PQgetisnull (result,
+                  row,
+                  fnum))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_assert (NULL != dst);
+  if (sizeof (struct GNUNET_TIME_Absolute) != *dst_size)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (sizeof (int64_t) !=
+      PQgetlength (result,
+                   row,
+                   fnum))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  res = (int64_t *) PQgetvalue (result,
+                               row,
+                               fnum);
+  if (INT64_MAX == *res)
+    *udst = GNUNET_TIME_UNIT_FOREVER_ABS;
+  else
+    udst->abs_value_us = GNUNET_ntohll ((uint64_t) *res);
+  return GNUNET_OK;
+}
+
+
 /**
  * Absolute time expected.
  *
@@ -430,8 +601,12 @@ struct GNUNET_PQ_ResultSpec
 GNUNET_PQ_result_spec_absolute_time (const char *name,
                                     struct GNUNET_TIME_Absolute *at)
 {
-  return GNUNET_PQ_result_spec_uint64 (name,
-                                      &at->abs_value_us);
+  struct GNUNET_PQ_ResultSpec res =
+    { &extract_abs_time,
+      NULL,
+      NULL,
+      (void *) at, sizeof (*at), (name), NULL };
+  return res;
 }
 
 
@@ -463,9 +638,8 @@ GNUNET_PQ_result_spec_absolute_time_nbo (const char *name,
  * @param[out] dst where to store the result
  * @return
  *   #GNUNET_YES if all results could be extracted
- *   #GNUNET_NO if at least one result was NULL
- *   #GNUNET_SYSERR if a result was invalid (non-existing field)
- */ 
+ *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
 static int
 extract_uint16 (void *cls,
                PGresult *result,
@@ -477,26 +651,36 @@ extract_uint16 (void *cls,
   uint16_t *udst = dst;
   const uint16_t *res;
   int fnum;
-  
+
+  (void) cls;
   fnum = PQfnumber (result,
                    fname);
   if (fnum < 0)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Field `%s' does not exist in result\n",
-               fname);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   if (PQgetisnull (result,
                   row,
                   fnum))
-    return GNUNET_NO;
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
   GNUNET_assert (NULL != dst);
   if (sizeof (uint16_t) != *dst_size)
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
+  if (sizeof (uint16_t) !=
+      PQgetlength (result,
+                   row,
+                   fnum))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
   res = (uint16_t *) PQgetvalue (result,
                                 row,
                                 fnum);
@@ -536,9 +720,8 @@ GNUNET_PQ_result_spec_uint16 (const char *name,
  * @param[out] dst where to store the result
  * @return
  *   #GNUNET_YES if all results could be extracted
- *   #GNUNET_NO if at least one result was NULL
- *   #GNUNET_SYSERR if a result was invalid (non-existing field)
- */ 
+ *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
 static int
 extract_uint32 (void *cls,
                PGresult *result,
@@ -550,26 +733,36 @@ extract_uint32 (void *cls,
   uint32_t *udst = dst;
   const uint32_t *res;
   int fnum;
-  
+
+  (void) cls;
   fnum = PQfnumber (result,
                    fname);
   if (fnum < 0)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Field `%s' does not exist in result\n",
-               fname);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   if (PQgetisnull (result,
                   row,
                   fnum))
-    return GNUNET_NO;
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
   GNUNET_assert (NULL != dst);
   if (sizeof (uint32_t) != *dst_size)
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
+  if (sizeof (uint32_t) !=
+      PQgetlength (result,
+                   row,
+                   fnum))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
   res = (uint32_t *) PQgetvalue (result,
                                 row,
                                 fnum);
@@ -590,7 +783,7 @@ GNUNET_PQ_result_spec_uint32 (const char *name,
                              uint32_t *u32)
 {
   struct GNUNET_PQ_ResultSpec res =
-    { &extract_uint32, 
+    { &extract_uint32,
       NULL,
       NULL,
       (void *) u32, sizeof (*u32), (name), NULL };
@@ -609,9 +802,8 @@ GNUNET_PQ_result_spec_uint32 (const char *name,
  * @param[out] dst where to store the result
  * @return
  *   #GNUNET_YES if all results could be extracted
- *   #GNUNET_NO if at least one result was NULL
- *   #GNUNET_SYSERR if a result was invalid (non-existing field)
- */ 
+ *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
 static int
 extract_uint64 (void *cls,
                PGresult *result,
@@ -623,26 +815,36 @@ extract_uint64 (void *cls,
   uint64_t *udst = dst;
   const uint64_t *res;
   int fnum;
-  
+
+  (void) cls;
   fnum = PQfnumber (result,
                    fname);
   if (fnum < 0)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Field `%s' does not exist in result\n",
-               fname);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   if (PQgetisnull (result,
                   row,
                   fnum))
-    return GNUNET_NO;
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
   GNUNET_assert (NULL != dst);
   if (sizeof (uint64_t) != *dst_size)
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
+  if (sizeof (uint64_t) !=
+      PQgetlength (result,
+                   row,
+                   fnum))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
   res = (uint64_t *) PQgetvalue (result,
                                 row,
                                 fnum);