LCOV - code coverage report
Current view: top level - pq - pq_result_helper.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 67 80 83.8 %
Date: 2017-11-25 11:31:41 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014, 2015, 2016 GNUnet e.V.
       4             : 
       5             :   TALER 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             :   TALER 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             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file pq/pq_result_helper.c
      18             :  * @brief functions to initialize parameter arrays
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include <gnunet/gnunet_util_lib.h>
      23             : #include "taler_pq_lib.h"
      24             : 
      25             : 
      26             : /**
      27             :  * Extract a currency amount from a query result according to the
      28             :  * given specification.
      29             :  *
      30             :  * @param result the result to extract the amount from
      31             :  * @param row which row of the result to extract the amount from (needed as results can have multiple rows)
      32             :  * @param val_name name of the column with the amount's "value", must include the substring "_val".
      33             :  * @param frac_name name of the column with the amount's "fractional" value, must include the substring "_frac".
      34             :  * @param curr_name name of the column with the amount's currency name, must include the substring "_curr".
      35             :  * @param[out] r_amount_nbo where to store the amount, in network byte order
      36             :  * @return
      37             :  *   #GNUNET_YES if all results could be extracted
      38             :  *   #GNUNET_NO if at least one result was NULL
      39             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
      40             :  */
      41             : static int
      42         367 : extract_amount_nbo_helper (PGresult *result,
      43             :                            int row,
      44             :                            const char *val_name,
      45             :                            const char *frac_name,
      46             :                            const char *curr_name,
      47             :                            struct TALER_AmountNBO *r_amount_nbo)
      48             : {
      49             :   int val_num;
      50             :   int frac_num;
      51             :   int curr_num;
      52             :   int len;
      53             : 
      54             :   /* These checks are simply to check that clients obey by our naming
      55             :      conventions, and not for any functional reason */
      56         367 :   GNUNET_assert (NULL !=
      57             :                  strstr (val_name,
      58             :                          "_val"));
      59         367 :   GNUNET_assert (NULL !=
      60             :                  strstr (frac_name,
      61             :                          "_frac"));
      62         367 :   GNUNET_assert (NULL !=
      63             :                  strstr (curr_name,
      64             :                          "_curr"));
      65             :   /* Set return value to invalid in case we don't finish */
      66         367 :   memset (r_amount_nbo,
      67             :           0,
      68             :           sizeof (struct TALER_AmountNBO));
      69         367 :   val_num = PQfnumber (result,
      70             :                        val_name);
      71         367 :   frac_num = PQfnumber (result,
      72             :                         frac_name);
      73         367 :   curr_num = PQfnumber (result,
      74             :                         curr_name);
      75         367 :   if (val_num < 0)
      76             :   {
      77           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
      78             :                 "Field `%s' does not exist in result\n",
      79             :                 val_name);
      80           0 :     return GNUNET_SYSERR;
      81             :   }
      82         367 :   if (frac_num < 0)
      83             :   {
      84           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
      85             :                 "Field `%s' does not exist in result\n",
      86             :                 frac_name);
      87           0 :     return GNUNET_SYSERR;
      88             :   }
      89         367 :   if (curr_num < 0)
      90             :   {
      91           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
      92             :                 "Field `%s' does not exist in result\n",
      93             :                 curr_name);
      94           0 :     return GNUNET_SYSERR;
      95             :   }
      96         367 :   if ( (PQgetisnull (result,
      97             :                      row,
      98         367 :                      val_num)) ||
      99         367 :        (PQgetisnull (result,
     100             :                      row,
     101         367 :                      frac_num)) ||
     102         367 :        (PQgetisnull (result,
     103             :                      row,
     104             :                      curr_num)) )
     105             :   {
     106           0 :     GNUNET_break (0);
     107           0 :     return GNUNET_NO;
     108             :   }
     109             :   /* Note that Postgres stores value in NBO internally,
     110             :      so no conversion needed in this case */
     111         367 :   r_amount_nbo->value = *(uint64_t *) PQgetvalue (result,
     112             :                                                   row,
     113             :                                                   val_num);
     114         367 :   r_amount_nbo->fraction = *(uint32_t *) PQgetvalue (result,
     115             :                                                      row,
     116             :                                                      frac_num);
     117         367 :   len = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
     118             :                     PQgetlength (result,
     119             :                                  row,
     120             :                                  curr_num));
     121         734 :   memcpy (r_amount_nbo->currency,
     122         367 :           PQgetvalue (result,
     123             :                       row,
     124             :                       curr_num),
     125             :           len);
     126         367 :   return GNUNET_OK;
     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 row row to extract data from
     136             :  * @param fname name (or prefix) of the fields to extract from
     137             :  * @param[in,out] dst_size where to store size of result, may be NULL
     138             :  * @param[out] dst where to store the result
     139             :  * @return
     140             :  *   #GNUNET_YES if all results could be extracted
     141             :  *   #GNUNET_NO if at least one result was NULL
     142             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
     143             :  */
     144             : static int
     145         121 : extract_amount_nbo (void *cls,
     146             :                     PGresult *result,
     147             :                     int row,
     148             :                     const char *fname,
     149             :                     size_t *dst_size,
     150             :                     void *dst)
     151             : {
     152             :   char *val_name;
     153             :   char *frac_name;
     154             :   char *curr_name;
     155             :   int ret;
     156             : 
     157         121 :   GNUNET_asprintf (&val_name,
     158             :                    "%s_val",
     159             :                    fname);
     160         121 :   GNUNET_asprintf (&frac_name,
     161             :                    "%s_frac",
     162             :                    fname);
     163         121 :   GNUNET_asprintf (&curr_name,
     164             :                    "%s_curr",
     165             :                    fname);
     166         121 :   ret = extract_amount_nbo_helper (result,
     167             :                                    row,
     168             :                                    val_name,
     169             :                                    frac_name,
     170             :                                    curr_name,
     171             :                                    dst);
     172         121 :   GNUNET_free (val_name);
     173         121 :   GNUNET_free (frac_name);
     174         121 :   GNUNET_free (curr_name);
     175         121 :   return ret;
     176             : }
     177             : 
     178             : 
     179             : /**
     180             :  * Currency amount expected.
     181             :  *
     182             :  * @param name name of the field in the table
     183             :  * @param[out] amount where to store the result
     184             :  * @return array entry for the result specification to use
     185             :  */
     186             : struct GNUNET_PQ_ResultSpec
     187         191 : TALER_PQ_result_spec_amount_nbo (const char *name,
     188             :                                  struct TALER_AmountNBO *amount)
     189             : {
     190         191 :   struct GNUNET_PQ_ResultSpec res =
     191             :     { &extract_amount_nbo, NULL, NULL,
     192             :       (void *) amount, sizeof (*amount),
     193             :       name, NULL };
     194         191 :   return res;
     195             : }
     196             : 
     197             : 
     198             : /**
     199             :  * Extract data from a Postgres database @a result at row @a row.
     200             :  *
     201             :  * @param cls closure
     202             :  * @param result where to extract data from
     203             :  * @param row row to extract data from
     204             :  * @param fname name (or prefix) of the fields to extract from
     205             :  * @param[in,out] dst_size where to store size of result, may be NULL
     206             :  * @param[out] dst where to store the result
     207             :  * @return
     208             :  *   #GNUNET_YES if all results could be extracted
     209             :  *   #GNUNET_NO if at least one result was NULL
     210             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
     211             :  */
     212             : static int
     213         246 : extract_amount (void *cls,
     214             :                 PGresult *result,
     215             :                 int row,
     216             :                 const char *fname,
     217             :                 size_t *dst_size,
     218             :                 void *dst)
     219             : {
     220         246 :   struct TALER_Amount *r_amount = dst;
     221             :   char *val_name;
     222             :   char *frac_name;
     223             :   char *curr_name;
     224             :   struct TALER_AmountNBO amount_nbo;
     225             :   int ret;
     226             : 
     227         246 :   GNUNET_asprintf (&val_name,
     228             :                    "%s_val",
     229             :                    fname);
     230         246 :   GNUNET_asprintf (&frac_name,
     231             :                    "%s_frac",
     232             :                    fname);
     233         246 :   GNUNET_asprintf (&curr_name,
     234             :                    "%s_curr",
     235             :                    fname);
     236         246 :   ret = extract_amount_nbo_helper (result,
     237             :                                    row,
     238             :                                    val_name,
     239             :                                    frac_name,
     240             :                                    curr_name,
     241             :                                    &amount_nbo);
     242         246 :   TALER_amount_ntoh (r_amount,
     243             :                      &amount_nbo);
     244         246 :   GNUNET_free (val_name);
     245         246 :   GNUNET_free (frac_name);
     246         246 :   GNUNET_free (curr_name);
     247         246 :   return ret;
     248             : }
     249             : 
     250             : 
     251             : /**
     252             :  * Currency amount expected.
     253             :  *
     254             :  * @param name name of the field in the table
     255             :  * @param[out] amount where to store the result
     256             :  * @return array entry for the result specification to use
     257             :  */
     258             : struct GNUNET_PQ_ResultSpec
     259         389 : TALER_PQ_result_spec_amount (const char *name,
     260             :                              struct TALER_Amount *amount)
     261             : {
     262         389 :   struct GNUNET_PQ_ResultSpec res =
     263             :     { &extract_amount, NULL, NULL,
     264             :       (void *) amount, sizeof (*amount),
     265             :       name, NULL };
     266         389 :   return res;
     267             : }
     268             : 
     269             : 
     270             : /**
     271             :  * Extract data from a Postgres database @a result at row @a row.
     272             :  *
     273             :  * @param cls closure
     274             :  * @param result where to extract data from
     275             :  * @param row row to extract data from
     276             :  * @param fname name (or prefix) of the fields to extract from
     277             :  * @param[in,out] dst_size where to store size of result, may be NULL
     278             :  * @param[out] dst where to store the result
     279             :  * @return
     280             :  *   #GNUNET_YES if all results could be extracted
     281             :  *   #GNUNET_NO if at least one result was NULL
     282             :  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
     283             :  */
     284             : static int
     285          57 : extract_json (void *cls,
     286             :               PGresult *result,
     287             :               int row,
     288             :               const char *fname,
     289             :               size_t *dst_size,
     290             :               void *dst)
     291             : {
     292          57 :   json_t **j_dst = dst;
     293             :   const char *res;
     294             :   int fnum;
     295             :   json_error_t json_error;
     296             :   size_t slen;
     297             : 
     298          57 :   fnum = PQfnumber (result,
     299             :                     fname);
     300          57 :   if (fnum < 0)
     301             :   {
     302           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     303             :                 "Field `%s' does not exist in result\n",
     304             :                 fname);
     305           0 :     return GNUNET_SYSERR;
     306             :   }
     307          57 :   if (PQgetisnull (result,
     308             :                    row,
     309             :                    fnum))
     310           0 :     return GNUNET_NO;
     311          57 :   slen = PQgetlength (result,
     312             :                       row,
     313             :                       fnum);
     314          57 :   res = (const char *) PQgetvalue (result,
     315             :                                    row,
     316             :                                    fnum);
     317          57 :   *j_dst = json_loadb (res,
     318             :                        slen,
     319             :                        JSON_REJECT_DUPLICATES,
     320             :                        &json_error);
     321          57 :   if (NULL == *j_dst)
     322             :   {
     323           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     324             :                 "Failed to parse JSON result for field `%s': %s (%s)\n",
     325             :                 fname,
     326             :                 json_error.text,
     327             :                 json_error.source);
     328           0 :     return GNUNET_SYSERR;
     329             :   }
     330          57 :   return GNUNET_OK;
     331             : }
     332             : 
     333             : 
     334             : /**
     335             :  * Function called to clean up memory allocated
     336             :  * by a #GNUNET_PQ_ResultConverter.
     337             :  *
     338             :  * @param cls closure
     339             :  * @param rd result data to clean up
     340             :  */
     341             : static void
     342          33 : clean_json (void *cls,
     343             :             void *rd)
     344             : {
     345          33 :   json_t **dst = rd;
     346             : 
     347          33 :   if (NULL != *dst)
     348             :   {
     349          33 :     json_decref (*dst);
     350          33 :     *dst = NULL;
     351             :   }
     352          33 : }
     353             : 
     354             : 
     355             : /**
     356             :  * json_t expected.
     357             :  *
     358             :  * @param name name of the field in the table
     359             :  * @param[out] jp where to store the result
     360             :  * @return array entry for the result specification to use
     361             :  */
     362             : struct GNUNET_PQ_ResultSpec
     363          98 : TALER_PQ_result_spec_json (const char *name,
     364             :                            json_t **jp)
     365             : {
     366          98 :   struct GNUNET_PQ_ResultSpec res =
     367             :     { &extract_json, &clean_json, NULL,
     368             :       (void *) jp, 0,
     369             :       name, NULL };
     370          98 :   return res;
     371             : }
     372             : 
     373             : /* end of pq_result_helper.c */

Generated by: LCOV version 1.13