lookup_statistics_counter_by_bucket.c (5210B)
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/lookup_statistics_counter_by_bucket.c 18 * @brief Implementation of the lookup_statistics_counter_by_bucket function for Postgres 19 * @author Martin Schanzenbach 20 */ 21 #include "platform.h" 22 #include <taler/taler_pq_lib.h> 23 #include "merchant-database/lookup_statistics_counter_by_bucket.h" 24 #include "helper.h" 25 #include "merchantdb_lib.h" 26 27 28 /** 29 * Context used for TALER_MERCHANTDB_lookup_statistics_counter_by_bucket(). 30 */ 31 struct LookupCounterStatisticsContext 32 { 33 /** 34 * Function to call with the results. 35 */ 36 TALER_MERCHANTDB_CounterByBucketStatisticsCallback 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 50 /** 51 * Function to be called with the results of a SELECT statement 52 * that has returned @a num_results results about token families. 53 * 54 * @param[in,out] cls of type `struct LookupCounterStatisticsContext *` 55 * @param result the postgres result 56 * @param num_results the number of results in @a result 57 */ 58 static void 59 lookup_statistics_counter_by_bucket_cb (void *cls, 60 PGresult *result, 61 unsigned int num_results) 62 { 63 struct LookupCounterStatisticsContext *tflc = cls; 64 65 for (unsigned int i = 0; i < num_results; i++) 66 { 67 char *description; 68 char *bucket_range; 69 uint64_t cumulative_number; 70 uint64_t bucket_start_epoch; 71 uint64_t bucket_end_epoch; 72 struct GNUNET_PQ_ResultSpec rs[] = { 73 GNUNET_PQ_result_spec_string ("description", 74 &description), 75 GNUNET_PQ_result_spec_uint64 ("bucket_start", 76 &bucket_start_epoch), 77 GNUNET_PQ_result_spec_uint64 ("bucket_end", 78 &bucket_end_epoch), 79 GNUNET_PQ_result_spec_string ("bucket_range", 80 &bucket_range), 81 GNUNET_PQ_result_spec_uint64 ("cumulative_number", 82 &cumulative_number), 83 GNUNET_PQ_result_spec_end 84 }; 85 struct GNUNET_TIME_Timestamp bucket_start; 86 struct GNUNET_TIME_Timestamp bucket_end; 87 88 if (GNUNET_OK != 89 GNUNET_PQ_extract_result (result, 90 rs, 91 i)) 92 { 93 GNUNET_break (0); 94 tflc->extract_failed = true; 95 return; 96 } 97 98 bucket_start = GNUNET_TIME_timestamp_from_s (bucket_start_epoch); 99 bucket_end = GNUNET_TIME_timestamp_from_s (bucket_end_epoch); 100 tflc->cb (tflc->cb_cls, 101 description, 102 bucket_start, 103 bucket_end, 104 bucket_range, 105 cumulative_number); 106 GNUNET_PQ_cleanup_result (rs); 107 } 108 } 109 110 111 enum GNUNET_DB_QueryStatus 112 TALER_MERCHANTDB_lookup_statistics_counter_by_bucket ( 113 struct TALER_MERCHANTDB_PostgresContext *pg, 114 const char *instance_id, 115 const char *slug, 116 TALER_MERCHANTDB_CounterByBucketStatisticsCallback cb, 117 void *cb_cls) 118 { 119 struct LookupCounterStatisticsContext context = { 120 .cb = cb, 121 .cb_cls = cb_cls, 122 /* Can be overwritten by the lookup_statistics_counter_by_bucket_cb */ 123 .extract_failed = false, 124 }; 125 struct GNUNET_PQ_QueryParam params[] = { 126 GNUNET_PQ_query_param_string (slug), 127 GNUNET_PQ_query_param_end 128 }; 129 enum GNUNET_DB_QueryStatus qs; 130 131 GNUNET_assert (NULL != pg->current_merchant_id); 132 GNUNET_assert (0 == strcmp (instance_id, 133 pg->current_merchant_id)); 134 check_connection (pg); 135 TMH_PQ_prepare_anon (pg, 136 "SELECT" 137 " description" 138 ",bucket_start" 139 ",bucket_range::TEXT" 140 ",merchant_statistics_bucket_end(bucket_start, bucket_range) AS bucket_end" 141 ",cumulative_number" 142 " FROM merchant_statistic_bucket_counter" 143 " JOIN merchant_statistic_bucket_meta" 144 " USING (bmeta_serial_id)" 145 " WHERE merchant_statistic_bucket_meta.slug=$1" 146 " AND merchant_statistic_bucket_meta.stype = 'number'"); 147 qs = GNUNET_PQ_eval_prepared_multi_select ( 148 pg->conn, 149 "", 150 params, 151 &lookup_statistics_counter_by_bucket_cb, 152 &context); 153 /* If there was an error inside the cb, return a hard error. */ 154 if (context.extract_failed) 155 { 156 GNUNET_break (0); 157 return GNUNET_DB_STATUS_HARD_ERROR; 158 } 159 return qs; 160 }