merchant

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

helper.h (5380B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 2023 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/helper.h
     18  * @brief shared internal definitions for postgres logic
     19  * @author Christian Grothoff
     20  */
     21 #ifndef HELPER_H
     22 #define HELPER_H
     23 
     24 #include <gnunet/gnunet_util_lib.h>
     25 #include <gnunet/gnunet_db_lib.h>
     26 #include <gnunet/gnunet_time_lib.h>
     27 #include <taler/taler_util.h>
     28 
     29 /**
     30  * Type of the "cls" argument given to each of the functions in
     31  * our API.
     32  */
     33 struct TALER_MERCHANTDB_PostgresContext
     34 {
     35 
     36   /**
     37    * Postgres connection handle.
     38    */
     39   struct GNUNET_PQ_Context *conn;
     40 
     41   /**
     42    * Underlying configuration.
     43    */
     44   const struct GNUNET_CONFIGURATION_Handle *cfg;
     45 
     46   /**
     47    * Name of the currently active transaction, NULL if none is active.
     48    */
     49   const char *transaction_name;
     50 
     51   /**
     52    * Instance id ("merchant_id") that the search_path is currently
     53    * pointing at, or NULL if no per-instance schema is selected.
     54    * Owned by this struct; set by TALER_MERCHANTDB_set_instance().
     55    */
     56   char *current_merchant_id;
     57 
     58   /**
     59    * merchant_serial corresponding to @e current_merchant_id, or 0
     60    * if no per-instance schema is selected.  Used as the suffix in
     61    * per-instance prepared-statement names.
     62    */
     63   uint64_t current_merchant_serial;
     64 
     65   /**
     66    * Public key of the currently selected instance.  Populated by
     67    * TALER_MERCHANTDB_set_instance() together with @e current_merchant_id
     68    * and @e current_merchant_serial.  Used by call sites that emit
     69    * cross-process events (e.g. order-pay notifications) which carry the
     70    * instance public key in their payload.
     71    */
     72   struct TALER_MerchantPublicKeyP current_merchant_pub;
     73 
     74 };
     75 
     76 
     77 /**
     78  * How many times have we connected to the DB.
     79  */
     80 extern uint64_t TMH_PG_prep_gen_;
     81 
     82 
     83 /**
     84  * Convert the signed @a limit of a paginated listing into the row
     85  * limit to pass to SQL.  The sign selects the iteration direction and
     86  * the magnitude the number of rows, but computing `-limit` directly is
     87  * undefined behaviour for `INT64_MIN`, and the resulting value would
     88  * reach Postgres as `LIMIT -9223372036854775808`, which errors out.
     89  * `INT64_MIN` is therefore saturated to `INT64_MAX`.
     90  *
     91  * @param limit signed limit as given by the caller
     92  * @return absolute value of @a limit, without signed overflow
     93  */
     94 static inline uint64_t
     95 TALER_MERCHANTDB_abs_limit (int64_t limit)
     96 {
     97   /* Postgres binds INT8 as a *signed* 64-bit integer, so a magnitude
     98      above INT64_MAX would reach LIMIT as a negative number. */
     99   if (INT64_MIN == limit)
    100     return (uint64_t) INT64_MAX;
    101   if (limit < 0)
    102     return (uint64_t) -limit;
    103   return (uint64_t) limit;
    104 }
    105 
    106 
    107 /**
    108  * Prepares SQL statement @a sql under @a name for
    109  * connection @a pg once.
    110  * Returns with #GNUNET_DB_STATUS_HARD_ERROR on failure.
    111  *
    112  * @param pg a `struct TALER_MERCHANTDB_PostgresContext`
    113  * @param name name to prepare the statement under
    114  * @param sql actual SQL text
    115  */
    116 #define PREPARE(pg,name,sql)                      \
    117         do {                                            \
    118           static unsigned long long gen;                \
    119                                                         \
    120           if (gen < TMH_PG_prep_gen_)                   \
    121           {                                             \
    122             struct GNUNET_PQ_PreparedStatement ps[] = { \
    123               GNUNET_PQ_make_prepare (name, sql),       \
    124               GNUNET_PQ_PREPARED_STATEMENT_END          \
    125             };                                          \
    126                                                         \
    127             if (GNUNET_OK !=                            \
    128                 GNUNET_PQ_prepare_statements (pg->conn, \
    129                                               ps))      \
    130             {                                           \
    131               GNUNET_break (0);                         \
    132               return GNUNET_DB_STATUS_HARD_ERROR;       \
    133             }                                           \
    134             gen = TMH_PG_prep_gen_;                     \
    135           }                                             \
    136         } while (0)
    137 
    138 
    139 /**
    140  * Prepares SQL statement @a sql under no name ("") for
    141  * connection @a pg.  Useful for prepared statements that
    142  * should not be cached.
    143  * Returns with #GNUNET_DB_STATUS_HARD_ERROR on failure.
    144  *
    145  * @param pg a `struct TALER_MERCHANTDB_PostgresContext`
    146  * @param sql actual SQL text
    147  */
    148 #define TMH_PQ_prepare_anon(pg,sql)              \
    149         do {                                     \
    150           if (GNUNET_OK !=                       \
    151               GNUNET_PQ_prepare_anon (pg->conn,  \
    152                                       sql)) {    \
    153             GNUNET_break (0);                    \
    154             return GNUNET_DB_STATUS_HARD_ERROR;  \
    155           } } while (0)
    156 
    157 
    158 #endif