merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

pg_lookup_transfers.c (8362B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 2022-2024 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 backenddb/pg_lookup_transfers.c
     18  * @brief Implementation of the lookup_transfers function for Postgres
     19  * @author Christian Grothoff
     20  */
     21 #include "taler/platform.h"
     22 #include <taler/taler_error_codes.h>
     23 #include <taler/taler_dbevents.h>
     24 #include <taler/taler_pq_lib.h>
     25 #include "pg_lookup_transfers.h"
     26 #include "pg_helper.h"
     27 
     28 
     29 /**
     30  * Closure for #lookup_transfers_cb().
     31  */
     32 struct LookupTransfersContext
     33 {
     34   /**
     35    * Function to call on results.
     36    */
     37   TALER_MERCHANTDB_TransferCallback cb;
     38 
     39   /**
     40    * Closure for @e cb.
     41    */
     42   void *cb_cls;
     43 
     44   /**
     45    * Postgres context.
     46    */
     47   struct PostgresClosure *pg;
     48 
     49   /**
     50    * Transaction status (set).
     51    */
     52   enum GNUNET_DB_QueryStatus qs;
     53 
     54 };
     55 
     56 
     57 /**
     58  * Function to be called with the results of a SELECT statement
     59  * that has returned @a num_results results.
     60  *
     61  * @param cls of type `struct LookupTransfersContext *`
     62  * @param result the postgres result
     63  * @param num_results the number of results in @a result
     64  */
     65 static void
     66 lookup_transfers_cb (void *cls,
     67                      PGresult *result,
     68                      unsigned int num_results)
     69 {
     70   struct LookupTransfersContext *ltc = cls;
     71 
     72   for (unsigned int i = 0; i<num_results; i++)
     73   {
     74     struct TALER_Amount credit_amount;
     75     struct TALER_WireTransferIdentifierRawP wtid;
     76     struct TALER_FullPayto payto_uri;
     77     char *exchange_url;
     78     uint64_t transfer_serial_id;
     79     uint64_t expected_transfer_serial_id = 0;
     80     struct GNUNET_TIME_Absolute execution_time;
     81     bool expected;
     82     struct GNUNET_PQ_ResultSpec rs[] = {
     83       TALER_PQ_result_spec_amount_with_currency ("credit_amount",
     84                                                  &credit_amount),
     85       GNUNET_PQ_result_spec_auto_from_type ("wtid",
     86                                             &wtid),
     87       GNUNET_PQ_result_spec_string ("payto_uri",
     88                                     &payto_uri.full_payto),
     89       GNUNET_PQ_result_spec_string ("exchange_url",
     90                                     &exchange_url),
     91       GNUNET_PQ_result_spec_uint64 ("credit_serial",
     92                                     &transfer_serial_id),
     93       GNUNET_PQ_result_spec_allow_null (
     94         GNUNET_PQ_result_spec_uint64 ("expected_credit_serial",
     95                                       &expected_transfer_serial_id),
     96         NULL),
     97       GNUNET_PQ_result_spec_absolute_time ("execution_time",
     98                                            &execution_time),
     99       GNUNET_PQ_result_spec_bool ("expected",
    100                                   &expected),
    101       GNUNET_PQ_result_spec_end
    102     };
    103 
    104     if (GNUNET_OK !=
    105         GNUNET_PQ_extract_result (result,
    106                                   rs,
    107                                   i))
    108     {
    109       GNUNET_break (0);
    110       ltc->qs = GNUNET_DB_STATUS_HARD_ERROR;
    111       return;
    112     }
    113     ltc->cb (ltc->cb_cls,
    114              &credit_amount,
    115              &wtid,
    116              payto_uri,
    117              exchange_url,
    118              transfer_serial_id,
    119              expected_transfer_serial_id,
    120              execution_time,
    121              expected);
    122     GNUNET_PQ_cleanup_result (rs);
    123   }
    124   ltc->qs = num_results;
    125 }
    126 
    127 
    128 enum GNUNET_DB_QueryStatus
    129 TMH_PG_lookup_transfers (void *cls,
    130                          const char *instance_id,
    131                          struct TALER_FullPayto payto_uri,
    132                          struct GNUNET_TIME_Timestamp before,
    133                          struct GNUNET_TIME_Timestamp after,
    134                          int64_t limit,
    135                          uint64_t offset,
    136                          enum TALER_EXCHANGE_YesNoAll expected,
    137                          TALER_MERCHANTDB_TransferCallback cb,
    138                          void *cb_cls)
    139 {
    140   struct PostgresClosure *pg = cls;
    141   uint64_t plimit = (uint64_t) ((limit < 0) ? -limit : limit);
    142   bool by_time = ( (! GNUNET_TIME_absolute_is_never (before.abs_time)) ||
    143                    (! GNUNET_TIME_absolute_is_zero (after.abs_time)) );
    144   struct LookupTransfersContext ltc = {
    145     .cb = cb,
    146     .cb_cls = cb_cls,
    147     .pg = pg
    148   };
    149   struct GNUNET_PQ_QueryParam params[] = {
    150     GNUNET_PQ_query_param_string (instance_id),
    151     GNUNET_PQ_query_param_timestamp (&before),
    152     GNUNET_PQ_query_param_timestamp (&after),
    153     GNUNET_PQ_query_param_uint64 (&offset),
    154     GNUNET_PQ_query_param_uint64 (&plimit),
    155     NULL == payto_uri.full_payto
    156     ? GNUNET_PQ_query_param_null () /* NULL: do not filter by payto URI */
    157     : GNUNET_PQ_query_param_string (payto_uri.full_payto),
    158     GNUNET_PQ_query_param_bool (! by_time),     /* $7: filter by time? */
    159     GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_ALL == expected), /* filter by expected? */
    160     GNUNET_PQ_query_param_bool (TALER_EXCHANGE_YNA_YES == expected),
    161 
    162     GNUNET_PQ_query_param_end
    163   };
    164   enum GNUNET_DB_QueryStatus qs;
    165 
    166   check_connection (pg);
    167   PREPARE (pg,
    168            "lookup_transfers_asc",
    169            "SELECT"
    170            " mt.credit_amount"
    171            ",mt.wtid"
    172            ",mac.payto_uri"
    173            ",mt.exchange_url"
    174            ",mt.credit_serial"
    175            ",mt.execution_time"
    176            ",mt.expected"
    177            ",met.expected_credit_serial"
    178            " FROM merchant_transfers mt"
    179            "  JOIN merchant_accounts mac"
    180            "    USING (account_serial)"
    181            "  LEFT JOIN merchant_expected_transfers met"
    182            "    ON mt.wtid = met.wtid"
    183            "    AND mt.account_serial = met.account_serial"
    184            "    AND mt.exchange_url = met.exchange_url"
    185            "    AND mt.expected"
    186            " WHERE ( $7 OR "
    187            "         (mt.execution_time < $2 AND"
    188            "          mt.execution_time >= $3) )"
    189            "   AND ( (CAST($6 AS TEXT) IS NULL) OR "
    190            "         (REGEXP_REPLACE(mac.payto_uri,'\\?.*','')"
    191            "         =REGEXP_REPLACE($6,'\\?.*','')) )"
    192            "   AND ( $8 OR "
    193            "         (mt.expected = $9) )"
    194            "   AND merchant_serial ="
    195            "     (SELECT merchant_serial"
    196            "        FROM merchant_instances"
    197            "       WHERE merchant_id=$1)"
    198            "   AND (mt.credit_serial > $4)"
    199            " ORDER BY mt.credit_serial ASC"
    200            " LIMIT $5");
    201   PREPARE (pg,
    202            "lookup_transfers_desc",
    203            "SELECT"
    204            " mt.credit_amount"
    205            ",mt.wtid"
    206            ",mac.payto_uri"
    207            ",mt.exchange_url"
    208            ",mt.credit_serial"
    209            ",mt.execution_time"
    210            ",mt.expected"
    211            ",met.expected_credit_serial"
    212            " FROM merchant_transfers mt"
    213            "  JOIN merchant_accounts mac"
    214            "    USING (account_serial)"
    215            "  LEFT JOIN merchant_expected_transfers met"
    216            "    ON mt.wtid = met.wtid"
    217            "    AND mt.account_serial = met.account_serial"
    218            "    AND mt.exchange_url = met.exchange_url"
    219            "    AND mt.expected"
    220            " WHERE ( $7 OR "
    221            "         (mt.execution_time < $2 AND"
    222            "          mt.execution_time >= $3) )"
    223            "   AND ( (CAST($6 AS TEXT) IS NULL) OR "
    224            "         (REGEXP_REPLACE(mac.payto_uri,'\\?.*','')"
    225            "         =REGEXP_REPLACE($6,'\\?.*','')) )"
    226            "   AND ( $8 OR "
    227            "         (mt.expected = $9) )"
    228            "   AND merchant_serial ="
    229            "     (SELECT merchant_serial"
    230            "        FROM merchant_instances"
    231            "       WHERE merchant_id=$1)"
    232            "   AND (mt.credit_serial < $4)"
    233            " ORDER BY mt.credit_serial DESC"
    234            " LIMIT $5");
    235   qs = GNUNET_PQ_eval_prepared_multi_select (
    236     pg->conn,
    237     (limit > 0)
    238     ? "lookup_transfers_asc"
    239     : "lookup_transfers_desc",
    240     params,
    241     &lookup_transfers_cb,
    242     &ltc);
    243   if (0 >= qs)
    244     return qs;
    245   return ltc.qs;
    246 }