LCOV - code coverage report
Current view: top level - backenddb - iterate_statistic_bucket_amounts.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.3 % 56 50
Test Date: 2026-09-04 23:42:01 Functions: 100.0 % 2 2

            Line data    Source code
       1              : /*
       2              :    This file is part of TALER
       3              :    Copyright (C) 2025 Taler Systems SA
       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 src/backenddb/iterate_statistic_bucket_amounts.c
      18              :  * @brief Implementation of the iterate_statistic_bucket_amounts function for Postgres
      19              :  * @author Martin Schanzenbach
      20              :  */
      21              : #include "platform.h"
      22              : #include <taler/taler_pq_lib.h>
      23              : #include "merchant-database/iterate_statistic_bucket_amounts.h"
      24              : #include "helper.h"
      25              : #include "merchantdb_lib.h"
      26              : 
      27              : 
      28              : /**
      29              :  * Context used for TALER_MERCHANTDB_iterate_statistic_bucket_amounts().
      30              :  */
      31              : struct LookupAmountStatisticsContext
      32              : {
      33              :   /**
      34              :    * Function to call with the results.
      35              :    */
      36              :   TALER_MERCHANTDB_AmountByBucketStatisticsCallback cb;
      37              : 
      38              :   /**
      39              :    * Closure for @a cb.
      40              :    */
      41              :   void *cb_cls;
      42              : 
      43              :   /**
      44              :    * Did database result extraction fail?
      45              :    */
      46              :   bool extract_failed;
      47              : 
      48              :   /**
      49              :    * Postgres context for array lookups
      50              :    */
      51              :   struct TALER_MERCHANTDB_PostgresContext *pg;
      52              : };
      53              : 
      54              : 
      55              : /**
      56              :  * Function to be called with the results of a SELECT statement
      57              :  * that has returned @a num_results results about token families.
      58              :  *
      59              :  * @param[in,out] cls of type `struct LookupAmountStatisticsContext *`
      60              :  * @param result the postgres result
      61              :  * @param num_results the number of results in @a result
      62              :  */
      63              : static void
      64            8 : lookup_statistics_amount_by_bucket_cb (void *cls,
      65              :                                        PGresult *result,
      66              :                                        unsigned int num_results)
      67              : {
      68            8 :   struct LookupAmountStatisticsContext *tflc = cls;
      69            8 :   struct TALER_Amount *amounts = NULL;
      70            8 :   char *resp_range = NULL;
      71            8 :   char *resp_desc = NULL;
      72              :   uint64_t cur_bucket_start_epoch;
      73              :   uint64_t cur_bucket_end_epoch;
      74              :   uint64_t bmeta_id_current;
      75            8 :   unsigned int amounts_len = 0;
      76              : 
      77           56 :   for (unsigned int i = 0; i < num_results; i++)
      78              :   {
      79              :     struct TALER_Amount cumulative_amount;
      80              :     char *description;
      81              :     char *bucket_range;
      82              :     uint64_t bmeta_id;
      83              :     uint64_t bucket_start_epoch;
      84              :     uint64_t bucket_end_epoch;
      85           48 :     struct GNUNET_PQ_ResultSpec rs[] = {
      86           48 :       GNUNET_PQ_result_spec_uint64 ("bmeta_serial_id",
      87              :                                     &bmeta_id),
      88           48 :       GNUNET_PQ_result_spec_string ("description",
      89              :                                     &description),
      90           48 :       GNUNET_PQ_result_spec_uint64 ("bucket_start",
      91              :                                     &bucket_start_epoch),
      92           48 :       GNUNET_PQ_result_spec_uint64 ("bucket_end",
      93              :                                     &bucket_end_epoch),
      94           48 :       GNUNET_PQ_result_spec_string ("bucket_range",
      95              :                                     &bucket_range),
      96           48 :       TALER_PQ_result_spec_amount_with_currency ("cumulative_amount",
      97              :                                                  &cumulative_amount),
      98              :       GNUNET_PQ_result_spec_end
      99              :     };
     100              : 
     101           48 :     if (GNUNET_OK !=
     102           48 :         GNUNET_PQ_extract_result (result,
     103              :                                   rs,
     104              :                                   i))
     105              :     {
     106            0 :       GNUNET_break (0);
     107            0 :       tflc->extract_failed = true;
     108            0 :       return;
     109              :     }
     110              :     /* Call callback if the bucket changed */
     111           48 :     if ( (NULL != resp_desc) &&
     112           40 :          ( (bmeta_id != bmeta_id_current) ||
     113           40 :            (bucket_start_epoch != cur_bucket_start_epoch) ||
     114            0 :            (0 != strcasecmp (resp_range,
     115              :                              bucket_range)) ) )
     116              :     {
     117              :       struct GNUNET_TIME_Timestamp bucket_start;
     118              :       struct GNUNET_TIME_Timestamp bucket_end;
     119              : 
     120           40 :       bucket_start = GNUNET_TIME_timestamp_from_s (cur_bucket_start_epoch);
     121           40 :       bucket_end = GNUNET_TIME_timestamp_from_s (cur_bucket_end_epoch);
     122           40 :       tflc->cb (tflc->cb_cls,
     123              :                 resp_desc,
     124              :                 bucket_start,
     125              :                 bucket_end,
     126              :                 resp_range,
     127              :                 amounts_len,
     128              :                 amounts);
     129           40 :       GNUNET_free (resp_range);
     130           40 :       GNUNET_free (resp_desc);
     131           40 :       GNUNET_array_grow (amounts,
     132              :                          amounts_len,
     133              :                          0);
     134              :     }
     135           48 :     if (NULL == resp_desc)
     136              :     {
     137           48 :       cur_bucket_end_epoch = bucket_end_epoch;
     138           48 :       cur_bucket_start_epoch = bucket_start_epoch;
     139           48 :       resp_range = GNUNET_strdup (bucket_range);
     140           48 :       resp_desc = GNUNET_strdup (description);
     141           48 :       bmeta_id_current = bmeta_id;
     142              :     }
     143           48 :     GNUNET_array_append (amounts,
     144              :                          amounts_len,
     145              :                          cumulative_amount);
     146           48 :     GNUNET_PQ_cleanup_result (rs);
     147              :   }
     148            8 :   if (0 != amounts_len)
     149              :   {
     150              :     struct GNUNET_TIME_Timestamp bucket_start;
     151              :     struct GNUNET_TIME_Timestamp bucket_end;
     152              : 
     153            8 :     bucket_start = GNUNET_TIME_timestamp_from_s (cur_bucket_start_epoch);
     154            8 :     bucket_end = GNUNET_TIME_timestamp_from_s (cur_bucket_end_epoch);
     155            8 :     tflc->cb (tflc->cb_cls,
     156              :               resp_desc,
     157              :               bucket_start,
     158              :               bucket_end,
     159              :               resp_range,
     160              :               amounts_len,
     161              :               amounts);
     162            8 :     GNUNET_array_grow (amounts,
     163              :                        amounts_len,
     164              :                        0);
     165            8 :     GNUNET_free (resp_range);
     166            8 :     GNUNET_free (resp_desc);
     167              :   }
     168              : }
     169              : 
     170              : 
     171              : enum GNUNET_DB_QueryStatus
     172            8 : TALER_MERCHANTDB_iterate_statistic_bucket_amounts (
     173              :   struct TALER_MERCHANTDB_PostgresContext *pg,
     174              :   const char *instance_id,
     175              :   const char *slug,
     176              :   TALER_MERCHANTDB_AmountByBucketStatisticsCallback cb,
     177              :   void *cb_cls)
     178              : {
     179            8 :   struct LookupAmountStatisticsContext context = {
     180              :     .cb = cb,
     181              :     .cb_cls = cb_cls,
     182              :     /* Can be overwritten by the lookup_statistics_amount_by_bucket_cb */
     183              :     .extract_failed = false,
     184              :     .pg = pg,
     185              :   };
     186            8 :   struct GNUNET_PQ_QueryParam params[] = {
     187            8 :     GNUNET_PQ_query_param_string (slug),
     188              :     GNUNET_PQ_query_param_end
     189              :   };
     190              :   enum GNUNET_DB_QueryStatus qs;
     191              : 
     192            8 :   GNUNET_assert (NULL != pg->current_merchant_id);
     193            8 :   GNUNET_assert (0 == strcmp (instance_id,
     194              :                               pg->current_merchant_id));
     195            8 :   TMH_PQ_prepare_anon (pg,
     196              :                        "SELECT"
     197              :                        " bmeta_serial_id"
     198              :                        ",description"
     199              :                        ",bucket_start"
     200              :                        ",bucket_range::TEXT"
     201              :                        ",merchant_statistics_bucket_end(bucket_start, bucket_range) AS bucket_end"
     202              :                        ",(cumulative_value,cumulative_frac,curr)::merchant.taler_amount_currency AS cumulative_amount"
     203              :                        " FROM merchant_statistic_bucket_amount"
     204              :                        " JOIN merchant_statistic_bucket_meta"
     205              :                        "   USING (bmeta_serial_id)"
     206              :                        " WHERE merchant_statistic_bucket_meta.slug=$1"
     207              :                        "   AND merchant_statistic_bucket_meta.stype='amount'");
     208            8 :   qs = GNUNET_PQ_eval_prepared_multi_select (
     209              :     pg->conn,
     210              :     "",
     211              :     params,
     212              :     &lookup_statistics_amount_by_bucket_cb,
     213              :     &context);
     214              :   /* If there was an error inside the cb, return a hard error. */
     215            8 :   if (context.extract_failed)
     216              :   {
     217            0 :     GNUNET_break (0);
     218            0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     219              :   }
     220            8 :   return qs;
     221              : }
        

Generated by: LCOV version 2.0-1