LCOV - code coverage report
Current view: top level - backenddb - iterate_orders.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.3 % 52 48
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) 2022, 2023, 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_orders.c
      18              :  * @brief Implementation of the iterate_orders function for Postgres
      19              :  * @author Iván Ávalos
      20              :  * @author Christian Grothoff
      21              :  */
      22              : #include "platform.h"
      23              : #include <taler/taler_pq_lib.h>
      24              : #include "merchant-database/iterate_orders.h"
      25              : #include "helper.h"
      26              : 
      27              : /**
      28              :  * Context used for TALER_MERCHANTDB_iterate_orders().
      29              :  */
      30              : struct LookupOrdersContext
      31              : {
      32              :   /**
      33              :    * Function to call with the results.
      34              :    */
      35              :   TALER_MERCHANTDB_OrdersCallback cb;
      36              : 
      37              :   /**
      38              :    * Closure for @a cb.
      39              :    */
      40              :   void *cb_cls;
      41              : 
      42              :   /**
      43              :    * Did database result extraction fail?
      44              :    */
      45              :   bool extract_failed;
      46              : };
      47              : 
      48              : 
      49              : /**
      50              :  * Function to be called with the results of a SELECT statement
      51              :  * that has returned @a num_results results about orders.
      52              :  *
      53              :  * @param[in,out] cls of type `struct LookupOrdersContext *`
      54              :  * @param result the postgres result
      55              :  * @param num_results the number of results in @a result
      56              :  */
      57              : static void
      58          164 : lookup_orders_cb (void *cls,
      59              :                   PGresult *result,
      60              :                   unsigned int num_results)
      61              : {
      62          164 :   struct LookupOrdersContext *plc = cls;
      63              : 
      64         3324 :   for (unsigned int i = 0; i < num_results; i++)
      65              :   {
      66              :     char *order_id;
      67              :     uint64_t order_serial;
      68              :     struct GNUNET_TIME_Timestamp ts;
      69         3160 :     struct GNUNET_PQ_ResultSpec rs[] = {
      70         3160 :       GNUNET_PQ_result_spec_string ("order_id",
      71              :                                     &order_id),
      72         3160 :       GNUNET_PQ_result_spec_uint64 ("order_serial",
      73              :                                     &order_serial),
      74         3160 :       GNUNET_PQ_result_spec_timestamp ("creation_time",
      75              :                                        &ts),
      76              :       GNUNET_PQ_result_spec_end
      77              :     };
      78              : 
      79         3160 :     if (GNUNET_OK !=
      80         3160 :         GNUNET_PQ_extract_result (result,
      81              :                                   rs,
      82              :                                   i))
      83              :     {
      84            0 :       GNUNET_break (0);
      85            0 :       plc->extract_failed = true;
      86            0 :       return;
      87              :     }
      88         3160 :     plc->cb (plc->cb_cls,
      89              :              order_id,
      90              :              order_serial,
      91              :              ts);
      92         3160 :     GNUNET_PQ_cleanup_result (rs);
      93              :   }
      94              : }
      95              : 
      96              : 
      97              : enum GNUNET_DB_QueryStatus
      98          164 : TALER_MERCHANTDB_iterate_orders (
      99              :   struct TALER_MERCHANTDB_PostgresContext *pg,
     100              :   const char *instance_id,
     101              :   const struct TALER_MERCHANTDB_OrderFilter *of,
     102              :   TALER_MERCHANTDB_OrdersCallback cb,
     103              :   void *cb_cls)
     104              : {
     105          164 :   struct LookupOrdersContext plc = {
     106              :     .cb = cb,
     107              :     .cb_cls = cb_cls
     108              :   };
     109          164 :   uint64_t limit = (of->delta > 0) ? of->delta : -of->delta;
     110          164 :   struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
     111          164 :   struct GNUNET_PQ_QueryParam params[] = {
     112              :     /* $1 */
     113          164 :     GNUNET_PQ_query_param_uint64 (&limit),
     114          164 :     GNUNET_PQ_query_param_uint64 (&of->start_row),
     115          164 :     GNUNET_PQ_query_param_timestamp (&of->date),
     116          164 :     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->paid)),
     117              :     /* $5 */
     118          164 :     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->paid)),
     119          164 :     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->refunded)),
     120          164 :     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->refunded)),
     121          164 :     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->wired)),
     122          164 :     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->wired)),
     123              :     /* $10 */
     124          164 :     GNUNET_PQ_query_param_bool (NULL == of->session_id),
     125          164 :     NULL == of->session_id
     126          164 :     ? GNUNET_PQ_query_param_null ()
     127          164 :     : GNUNET_PQ_query_param_string (of->session_id),
     128          164 :     GNUNET_PQ_query_param_bool (NULL == of->fulfillment_url),
     129          164 :     NULL == of->fulfillment_url
     130          164 :     ? GNUNET_PQ_query_param_null ()
     131          164 :     : GNUNET_PQ_query_param_string (of->fulfillment_url),
     132          164 :     NULL == of->summary_filter
     133          164 :     ? GNUNET_PQ_query_param_null ()
     134          164 :     : GNUNET_PQ_query_param_string (of->summary_filter),
     135          164 :     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL == of->expired)),
     136          164 :     GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES == of->expired)),
     137          164 :     GNUNET_PQ_query_param_timestamp (&now),
     138              :     GNUNET_PQ_query_param_end
     139              :   };
     140              :   enum GNUNET_DB_QueryStatus qs;
     141              : 
     142          164 :   GNUNET_assert (NULL != pg->current_merchant_id);
     143          164 :   GNUNET_assert (0 == strcmp (instance_id,
     144              :                               pg->current_merchant_id));
     145          164 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     146              :               "Looking up orders, using filter paid: %d, refunded: %d, wired: %d, expired: %d\n",
     147              :               of->paid,
     148              :               of->refunded,
     149              :               of->wired,
     150              :               of->expired);
     151              : 
     152          164 :   if (of->delta > 0)
     153              :   {
     154          123 :     TMH_PQ_prepare_anon (pg,
     155              :                          "(SELECT"
     156              :                          " order_id"
     157              :                          ",order_serial"
     158              :                          ",creation_time"
     159              :                          " FROM merchant_orders"
     160              :                          " WHERE order_serial > $2"
     161              :                          "   AND"
     162              :                          "    creation_time > $3"
     163              :                          "   AND ($4 OR "
     164              :                          "    NOT CAST($5 AS BOOL))" /* unclaimed orders are never paid */
     165              :                          "   AND ($6 OR "
     166              :                          "    NOT CAST($7 AS BOOL))"/* unclaimed orders are never refunded */
     167              :                          "   AND ($8 OR "
     168              :                          "    NOT CAST($9 AS BOOL))" /* unclaimed orders are never wired */
     169              :                          "   AND"
     170              :                          "    (order_serial NOT IN"
     171              :                          "     (SELECT order_serial"
     172              :                          "      FROM merchant_contract_terms))" /* only select unclaimed orders */
     173              :                          "   AND ($10 OR "
     174              :                          "     ($11 = session_id))"
     175              :                          "   AND ($12 OR "
     176              :                          "     ($13 = fulfillment_url))"
     177              :                          "   AND ( ($14::TEXT IS NULL) OR "
     178              :                          "         (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )"
     179              :                          "   AND ($15 OR"
     180              :                          "        (CAST($16 AS BOOL) = (pay_deadline < $17)))"
     181              :                          " ORDER BY order_serial ASC"
     182              :                          " LIMIT $1)"
     183              :                          "UNION " /* union ensures elements are distinct! */
     184              :                          "(SELECT"
     185              :                          " order_id"
     186              :                          ",order_serial"
     187              :                          ",creation_time"
     188              :                          " FROM merchant_contract_terms"
     189              :                          " WHERE order_serial > $2"
     190              :                          "   AND"
     191              :                          "    creation_time > $3"
     192              :                          "   AND ($4 OR "
     193              :                          "    (CAST($5 AS BOOL) = paid))"
     194              :                          "   AND ($6 OR "
     195              :                          "    (CAST($7 AS BOOL) = (order_serial IN"
     196              :                          "     (SELECT order_serial "
     197              :                          "      FROM merchant_refunds))))"
     198              :                          "   AND ($8 OR"
     199              :                          "    (CAST($9 AS BOOL) = wired))"
     200              :                          "   AND ($10 OR "
     201              :                          "     ($11 = session_id))"
     202              :                          "   AND ($12 OR "
     203              :                          "     ($13 = fulfillment_url))"
     204              :                          "   AND ( ($14::TEXT IS NULL) OR "
     205              :                          "         (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )"
     206              :                          "   AND ($15 OR"
     207              :                          "        (CAST($16 AS BOOL) = ((NOT paid) AND"
     208              :                          "                              (pay_deadline < $17))))"
     209              :                          " ORDER BY order_serial ASC"
     210              :                          " LIMIT $1)"
     211              :                          " ORDER BY order_serial ASC"
     212              :                          " LIMIT $1");
     213              :   }
     214              :   else
     215              :   {
     216           41 :     TMH_PQ_prepare_anon (pg,
     217              :                          "(SELECT"
     218              :                          " order_id"
     219              :                          ",order_serial"
     220              :                          ",creation_time"
     221              :                          " FROM merchant_orders"
     222              :                          " WHERE order_serial < $2"
     223              :                          "   AND"
     224              :                          "    creation_time < $3"
     225              :                          "   AND ($4 OR "
     226              :                          "    NOT CAST($5 AS BOOL))" /* unclaimed orders are never paid */
     227              :                          "   AND ($6 OR "
     228              :                          "    NOT CAST($7 AS BOOL))"/* unclaimed orders are never refunded */
     229              :                          "   AND ($8 OR "
     230              :                          "    NOT CAST($9 AS BOOL))" /* unclaimed orders are never wired */
     231              :                          "   AND"
     232              :                          "    order_serial NOT IN"
     233              :                          "     (SELECT order_serial"
     234              :                          "      FROM merchant_contract_terms)" /* only select unclaimed orders */
     235              :                          "   AND ($10 OR "
     236              :                          "     ($11 = session_id))"
     237              :                          "   AND ($12 OR "
     238              :                          "     ($13 = fulfillment_url))"
     239              :                          "   AND ( ($14::TEXT IS NULL) OR "
     240              :                          "         (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )"
     241              :                          "   AND ($15 OR"
     242              :                          "        (CAST($16 AS BOOL) = (pay_deadline < $17)))"
     243              :                          " ORDER BY order_serial DESC"
     244              :                          " LIMIT $1)"
     245              :                          "UNION " /* union ensures elements are distinct! */
     246              :                          "(SELECT"
     247              :                          " order_id"
     248              :                          ",order_serial"
     249              :                          ",creation_time"
     250              :                          " FROM merchant_contract_terms"
     251              :                          " WHERE order_serial < $2"
     252              :                          "   AND"
     253              :                          "    creation_time < $3"
     254              :                          "   AND ($4 OR "
     255              :                          "    (CAST($5 AS BOOL) = paid))"
     256              :                          "   AND ($6 OR "
     257              :                          "    (CAST($7 AS BOOL) = (order_serial IN"
     258              :                          "     (SELECT order_serial "
     259              :                          "      FROM merchant_refunds))))"
     260              :                          "   AND ($8 OR"
     261              :                          "     (CAST($9 AS BOOL) = wired))"
     262              :                          "   AND ($10 OR "
     263              :                          "     ($11 = session_id))"
     264              :                          "   AND ($12 OR "
     265              :                          "     ($13 = fulfillment_url))"
     266              :                          "   AND ( ($14::TEXT IS NULL) OR "
     267              :                          "         (LOWER(contract_terms ->> 'summary') LIKE LOWER($14)) )"
     268              :                          "   AND ($15 OR"
     269              :                          "        (CAST($16 AS BOOL) = ((NOT paid) AND"
     270              :                          "                              (pay_deadline < $17))))"
     271              :                          " ORDER BY order_serial DESC"
     272              :                          " LIMIT $1)"
     273              :                          " ORDER BY order_serial DESC"
     274              :                          " LIMIT $1");
     275              :   }
     276          164 :   qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
     277              :                                              "",
     278              :                                              params,
     279              :                                              &lookup_orders_cb,
     280              :                                              &plc);
     281          164 :   if (plc.extract_failed)
     282            0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     283          164 :   return qs;
     284              : }
        

Generated by: LCOV version 2.0-1