LCOV - code coverage report
Current view: top level - syncdb - plugin_syncdb_postgres.c (source / functions) Hit Total Coverage
Test: GNU Taler sync coverage report Lines: 20 500 4.0 %
Date: 2022-08-25 06:17:07 Functions: 2 20 10.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   (C) 2014--2021 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Lesser 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 ANASTASISABILITY 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 sync/plugin_syncdb_postgres.c
      18             :  * @brief database helper functions for postgres used by sync
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include <gnunet/gnunet_util_lib.h>
      23             : #include <gnunet/gnunet_db_lib.h>
      24             : #include <gnunet/gnunet_pq_lib.h>
      25             : #include <taler/taler_pq_lib.h>
      26             : #include "sync_database_plugin.h"
      27             : #include "sync_database_lib.h"
      28             : 
      29             : /**
      30             :  * Type of the "cls" argument given to each of the functions in
      31             :  * our API.
      32             :  */
      33             : struct PostgresClosure
      34             : {
      35             : 
      36             :   /**
      37             :    * Postgres connection handle.
      38             :    */
      39             :   struct GNUNET_PQ_Context *conn;
      40             : 
      41             :   /**
      42             :    * Directory with SQL statements to run to create tables.
      43             :    */
      44             :   char *sql_dir;
      45             : 
      46             :   /**
      47             :    * Underlying configuration.
      48             :    */
      49             :   const struct GNUNET_CONFIGURATION_Handle *cfg;
      50             : 
      51             :   /**
      52             :    * Name of the currently active transaction, NULL if none is active.
      53             :    */
      54             :   const char *transaction_name;
      55             : 
      56             :   /**
      57             :    * Currency we accept payments in.
      58             :    */
      59             :   char *currency;
      60             : 
      61             :   /**
      62             :    * Did we initialize the prepared statements
      63             :    * for this session?
      64             :    */
      65             :   bool init;
      66             : 
      67             : };
      68             : 
      69             : 
      70             : /**
      71             :  * Drop sync tables
      72             :  *
      73             :  * @param cls closure our `struct Plugin`
      74             :  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
      75             :  */
      76             : static enum GNUNET_GenericReturnValue
      77           0 : postgres_drop_tables (void *cls)
      78             : {
      79           0 :   struct PostgresClosure *pg = cls;
      80             :   struct GNUNET_PQ_Context *conn;
      81             :   enum GNUNET_GenericReturnValue ret;
      82             : 
      83           0 :   if (NULL != pg->conn)
      84             :   {
      85           0 :     GNUNET_PQ_disconnect (pg->conn);
      86           0 :     pg->conn = NULL;
      87           0 :     pg->init = false;
      88             :   }
      89           0 :   conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
      90             :                                      "syncdb-postgres",
      91             :                                      NULL,
      92             :                                      NULL,
      93             :                                      NULL);
      94           0 :   if (NULL == conn)
      95           0 :     return GNUNET_SYSERR;
      96           0 :   ret = GNUNET_PQ_exec_sql (conn,
      97             :                             "drop");
      98           0 :   GNUNET_PQ_disconnect (conn);
      99           0 :   return ret;
     100             : }
     101             : 
     102             : 
     103             : /**
     104             :  * Establish connection to the database.
     105             :  *
     106             :  * @param cls plugin context
     107             :  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
     108             :  */
     109             : static enum GNUNET_GenericReturnValue
     110           0 : prepare_statements (void *cls)
     111             : {
     112           0 :   struct PostgresClosure *pg = cls;
     113           0 :   struct GNUNET_PQ_PreparedStatement ps[] = {
     114           0 :     GNUNET_PQ_make_prepare ("account_insert",
     115             :                             "INSERT INTO accounts "
     116             :                             "(account_pub"
     117             :                             ",expiration_date"
     118             :                             ") VALUES "
     119             :                             "($1,$2);",
     120             :                             2),
     121           0 :     GNUNET_PQ_make_prepare ("payment_insert",
     122             :                             "INSERT INTO payments "
     123             :                             "(account_pub"
     124             :                             ",order_id"
     125             :                             ",token"
     126             :                             ",timestamp"
     127             :                             ",amount_val"
     128             :                             ",amount_frac"
     129             :                             ") VALUES "
     130             :                             "($1,$2,$3,$4,$5,$6);",
     131             :                             6),
     132           0 :     GNUNET_PQ_make_prepare ("payment_done",
     133             :                             "UPDATE payments "
     134             :                             "SET"
     135             :                             " paid=TRUE "
     136             :                             "WHERE"
     137             :                             "  order_id=$1"
     138             :                             " AND"
     139             :                             "  account_pub=$2"
     140             :                             " AND"
     141             :                             "  paid=FALSE;",
     142             :                             2),
     143           0 :     GNUNET_PQ_make_prepare ("account_update",
     144             :                             "UPDATE accounts "
     145             :                             "SET"
     146             :                             " expiration_date=$1 "
     147             :                             "WHERE"
     148             :                             " account_pub=$2;",
     149             :                             2),
     150           0 :     GNUNET_PQ_make_prepare ("account_select",
     151             :                             "SELECT"
     152             :                             " expiration_date "
     153             :                             "FROM"
     154             :                             " accounts "
     155             :                             "WHERE"
     156             :                             " account_pub=$1;",
     157             :                             1),
     158           0 :     GNUNET_PQ_make_prepare ("payments_select",
     159             :                             "SELECT"
     160             :                             " account_pub"
     161             :                             ",order_id"
     162             :                             ",amount_val"
     163             :                             ",amount_frac"
     164             :                             " FROM payments"
     165             :                             " WHERE paid=FALSE;",
     166             :                             0),
     167           0 :     GNUNET_PQ_make_prepare ("payments_select_by_account",
     168             :                             "SELECT"
     169             :                             " timestamp"
     170             :                             ",order_id"
     171             :                             ",token"
     172             :                             ",amount_val"
     173             :                             ",amount_frac"
     174             :                             " FROM payments"
     175             :                             " WHERE"
     176             :                             "  paid=FALSE"
     177             :                             " AND"
     178             :                             "  account_pub=$1;",
     179             :                             1),
     180           0 :     GNUNET_PQ_make_prepare ("gc_accounts",
     181             :                             "DELETE FROM accounts "
     182             :                             "WHERE"
     183             :                             " expiration_date < $1;",
     184             :                             1),
     185           0 :     GNUNET_PQ_make_prepare ("gc_pending_payments",
     186             :                             "DELETE FROM payments "
     187             :                             "WHERE"
     188             :                             "  paid=FALSE"
     189             :                             " AND"
     190             :                             "  timestamp < $1;",
     191             :                             1),
     192           0 :     GNUNET_PQ_make_prepare ("backup_insert",
     193             :                             "INSERT INTO backups "
     194             :                             "(account_pub"
     195             :                             ",account_sig"
     196             :                             ",prev_hash"
     197             :                             ",backup_hash"
     198             :                             ",data"
     199             :                             ") VALUES "
     200             :                             "($1,$2,$3,$4,$5);",
     201             :                             5),
     202           0 :     GNUNET_PQ_make_prepare ("backup_update",
     203             :                             "UPDATE backups "
     204             :                             " SET"
     205             :                             " backup_hash=$1"
     206             :                             ",account_sig=$2"
     207             :                             ",prev_hash=$3"
     208             :                             ",data=$4"
     209             :                             " WHERE"
     210             :                             "   account_pub=$5"
     211             :                             "  AND"
     212             :                             "   backup_hash=$6;",
     213             :                             6),
     214           0 :     GNUNET_PQ_make_prepare ("backup_select_hash",
     215             :                             "SELECT "
     216             :                             " backup_hash "
     217             :                             "FROM"
     218             :                             " backups "
     219             :                             "WHERE"
     220             :                             " account_pub=$1;",
     221             :                             1),
     222           0 :     GNUNET_PQ_make_prepare ("backup_select",
     223             :                             "SELECT "
     224             :                             " account_sig"
     225             :                             ",prev_hash"
     226             :                             ",backup_hash"
     227             :                             ",data "
     228             :                             "FROM"
     229             :                             " backups "
     230             :                             "WHERE"
     231             :                             " account_pub=$1;",
     232             :                             1),
     233           0 :     GNUNET_PQ_make_prepare ("do_commit",
     234             :                             "COMMIT",
     235             :                             0),
     236             :     GNUNET_PQ_PREPARED_STATEMENT_END
     237             :   };
     238             :   enum GNUNET_GenericReturnValue ret;
     239             : 
     240           0 :   ret = GNUNET_PQ_prepare_statements (pg->conn,
     241             :                                       ps);
     242           0 :   if (GNUNET_OK != ret)
     243           0 :     return ret;
     244           0 :   pg->init = true;
     245           0 :   return GNUNET_OK;
     246             : }
     247             : 
     248             : 
     249             : /**
     250             :  * Connect to the database if the connection does not exist yet.
     251             :  *
     252             :  * @param pg the plugin-specific state
     253             :  * @param skip_prepare true if we should skip prepared statement setup
     254             :  * @return #GNUNET_OK on success
     255             :  */
     256             : static enum GNUNET_GenericReturnValue
     257           1 : internal_setup (struct PostgresClosure *pg,
     258             :                 bool skip_prepare)
     259             : {
     260           1 :   if (NULL == pg->conn)
     261             :   {
     262             : #if AUTO_EXPLAIN
     263             :     /* Enable verbose logging to see where queries do not
     264             :        properly use indices */
     265             :     struct GNUNET_PQ_ExecuteStatement es[] = {
     266             :       GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
     267             :       GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
     268             :       GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
     269             :       GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
     270             :       /* https://wiki.postgresql.org/wiki/Serializable suggests to really
     271             :          force the default to 'serializable' if SSI is to be used. */
     272             :       GNUNET_PQ_make_try_execute (
     273             :         "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
     274             :       GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
     275             :       GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
     276             :       GNUNET_PQ_EXECUTE_STATEMENT_END
     277             :     };
     278             : #else
     279           1 :     struct GNUNET_PQ_ExecuteStatement *es = NULL;
     280             : #endif
     281             :     struct GNUNET_PQ_Context *db_conn;
     282             : 
     283           1 :     db_conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
     284             :                                           "syncdb-postgres",
     285             :                                           NULL,
     286             :                                           es,
     287             :                                           NULL);
     288           1 :     if (NULL == db_conn)
     289           1 :       return GNUNET_SYSERR;
     290           0 :     pg->conn = db_conn;
     291             :   }
     292           0 :   if (NULL == pg->transaction_name)
     293           0 :     GNUNET_PQ_reconnect_if_down (pg->conn);
     294           0 :   if (pg->init)
     295           0 :     return GNUNET_OK;
     296           0 :   if (skip_prepare)
     297           0 :     return GNUNET_OK;
     298           0 :   return prepare_statements (pg);
     299             : }
     300             : 
     301             : 
     302             : /**
     303             :  * Do a pre-flight check that we are not in an uncommitted transaction.
     304             :  * If we are, try to commit the previous transaction and output a warning.
     305             :  * Does not return anything, as we will continue regardless of the outcome.
     306             :  *
     307             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
     308             :  * @return #GNUNET_OK if everything is fine
     309             :  *         #GNUNET_NO if a transaction was rolled back
     310             :  *         #GNUNET_SYSERR on hard errors
     311             :  */
     312             : static enum GNUNET_GenericReturnValue
     313           0 : postgres_preflight (void *cls)
     314             : {
     315           0 :   struct PostgresClosure *pg = cls;
     316           0 :   struct GNUNET_PQ_ExecuteStatement es[] = {
     317           0 :     GNUNET_PQ_make_execute ("ROLLBACK"),
     318             :     GNUNET_PQ_EXECUTE_STATEMENT_END
     319             :   };
     320             : 
     321           0 :   if (! pg->init)
     322             :   {
     323           0 :     if (GNUNET_OK !=
     324           0 :         internal_setup (pg,
     325             :                         false))
     326             :     {
     327           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     328             :                   "Failed to ensure DB is initialized\n");
     329           0 :       return GNUNET_SYSERR;
     330             :     }
     331             :   }
     332           0 :   if (NULL == pg->transaction_name)
     333           0 :     return GNUNET_OK; /* all good */
     334           0 :   if (GNUNET_OK ==
     335           0 :       GNUNET_PQ_exec_statements (pg->conn,
     336             :                                  es))
     337             :   {
     338           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     339             :                 "BUG: Preflight check rolled back transaction `%s'!\n",
     340             :                 pg->transaction_name);
     341             :   }
     342             :   else
     343             :   {
     344           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     345             :                 "BUG: Preflight check failed to rollback transaction `%s'!\n",
     346             :                 pg->transaction_name);
     347             :   }
     348           0 :   pg->transaction_name = NULL;
     349           0 :   return GNUNET_NO;
     350             : }
     351             : 
     352             : 
     353             : /**
     354             :  * Check that the database connection is still up.
     355             :  *
     356             :  * @param cls a `struct PostgresClosure` with connection to check
     357             :  */
     358             : static void
     359           0 : check_connection (void *cls)
     360             : {
     361           0 :   struct PostgresClosure *pg = cls;
     362             : 
     363           0 :   GNUNET_PQ_reconnect_if_down (pg->conn);
     364           0 : }
     365             : 
     366             : 
     367             : /**
     368             :  * Start a transaction.
     369             :  *
     370             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
     371             :  * @param name unique name identifying the transaction (for debugging),
     372             :  *             must point to a constant
     373             :  * @return #GNUNET_OK on success
     374             :  */
     375             : static enum GNUNET_GenericReturnValue
     376           0 : begin_transaction (void *cls,
     377             :                    const char *name)
     378             : {
     379           0 :   struct PostgresClosure *pg = cls;
     380           0 :   struct GNUNET_PQ_ExecuteStatement es[] = {
     381           0 :     GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
     382             :     GNUNET_PQ_EXECUTE_STATEMENT_END
     383             :   };
     384             : 
     385           0 :   check_connection (pg);
     386           0 :   postgres_preflight (pg);
     387           0 :   pg->transaction_name = name;
     388           0 :   if (GNUNET_OK !=
     389           0 :       GNUNET_PQ_exec_statements (pg->conn,
     390             :                                  es))
     391             :   {
     392           0 :     TALER_LOG_ERROR ("Failed to start transaction\n");
     393           0 :     GNUNET_break (0);
     394           0 :     return GNUNET_SYSERR;
     395             :   }
     396           0 :   return GNUNET_OK;
     397             : }
     398             : 
     399             : 
     400             : /**
     401             :  * Roll back the current transaction of a database connection.
     402             :  *
     403             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
     404             :  */
     405             : static void
     406           0 : rollback (void *cls)
     407             : {
     408           0 :   struct PostgresClosure *pg = cls;
     409           0 :   struct GNUNET_PQ_ExecuteStatement es[] = {
     410           0 :     GNUNET_PQ_make_execute ("ROLLBACK"),
     411             :     GNUNET_PQ_EXECUTE_STATEMENT_END
     412             :   };
     413             : 
     414           0 :   if (GNUNET_OK !=
     415           0 :       GNUNET_PQ_exec_statements (pg->conn,
     416             :                                  es))
     417             :   {
     418           0 :     TALER_LOG_ERROR ("Failed to rollback transaction\n");
     419           0 :     GNUNET_break (0);
     420             :   }
     421           0 :   pg->transaction_name = NULL;
     422           0 : }
     423             : 
     424             : 
     425             : /**
     426             :  * Commit the current transaction of a database connection.
     427             :  *
     428             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
     429             :  * @return transaction status code
     430             :  */
     431             : static enum GNUNET_DB_QueryStatus
     432           0 : commit_transaction (void *cls)
     433             : {
     434           0 :   struct PostgresClosure *pg = cls;
     435             :   enum GNUNET_DB_QueryStatus qs;
     436           0 :   struct GNUNET_PQ_QueryParam no_params[] = {
     437             :     GNUNET_PQ_query_param_end
     438             :   };
     439             : 
     440           0 :   qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
     441             :                                            "do_commit",
     442             :                                            no_params);
     443           0 :   pg->transaction_name = NULL;
     444           0 :   return qs;
     445             : }
     446             : 
     447             : 
     448             : /**
     449             :  * Function called to perform "garbage collection" on the
     450             :  * database, expiring records we no longer require.  Deletes
     451             :  * all user records that are not paid up (and by cascade deletes
     452             :  * the associated recovery documents). Also deletes expired
     453             :  * truth and financial records older than @a fin_expire.
     454             :  *
     455             :  * @param cls closure
     456             :  * @param expire_backups backups older than the given time stamp should be garbage collected
     457             :  * @param expire_pending_payments payments still pending from since before
     458             :  *            this value should be garbage collected
     459             :  * @return transaction status
     460             :  */
     461             : static enum GNUNET_DB_QueryStatus
     462           0 : postgres_gc (void *cls,
     463             :              struct GNUNET_TIME_Absolute expire_backups,
     464             :              struct GNUNET_TIME_Absolute expire_pending_payments)
     465             : {
     466           0 :   struct PostgresClosure *pg = cls;
     467           0 :   struct GNUNET_PQ_QueryParam params[] = {
     468           0 :     GNUNET_PQ_query_param_absolute_time (&expire_backups),
     469             :     GNUNET_PQ_query_param_end
     470             :   };
     471           0 :   struct GNUNET_PQ_QueryParam params2[] = {
     472           0 :     GNUNET_PQ_query_param_absolute_time (&expire_pending_payments),
     473             :     GNUNET_PQ_query_param_end
     474             :   };
     475             :   enum GNUNET_DB_QueryStatus qs;
     476             : 
     477           0 :   check_connection (pg);
     478           0 :   postgres_preflight (pg);
     479           0 :   qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
     480             :                                            "gc_accounts",
     481             :                                            params);
     482           0 :   if (qs < 0)
     483           0 :     return qs;
     484           0 :   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
     485             :                                              "gc_pending_payments",
     486             :                                              params2);
     487             : }
     488             : 
     489             : 
     490             : /**
     491             :  * Store payment. Used to begin a payment, not indicative
     492             :  * that the payment actually was made. (That is done
     493             :  * when we increment the account's lifetime.)
     494             :  *
     495             :  * @param cls closure
     496             :  * @param account_pub account to store @a backup under
     497             :  * @param order_id order we create
     498             :  * @param token claim token to use, NULL for none
     499             :  * @param amount how much we asked for
     500             :  * @return transaction status
     501             :  */
     502             : static enum SYNC_DB_QueryStatus
     503           0 : postgres_store_payment (void *cls,
     504             :                         const struct SYNC_AccountPublicKeyP *account_pub,
     505             :                         const char *order_id,
     506             :                         const struct TALER_ClaimTokenP *token,
     507             :                         const struct TALER_Amount *amount)
     508             : {
     509           0 :   struct PostgresClosure *pg = cls;
     510             :   enum GNUNET_DB_QueryStatus qs;
     511             :   struct TALER_ClaimTokenP tok;
     512           0 :   struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
     513           0 :   struct GNUNET_PQ_QueryParam params[] = {
     514           0 :     GNUNET_PQ_query_param_auto_from_type (account_pub),
     515           0 :     GNUNET_PQ_query_param_string (order_id),
     516           0 :     GNUNET_PQ_query_param_auto_from_type (&tok),
     517           0 :     GNUNET_PQ_query_param_timestamp (&now),
     518           0 :     TALER_PQ_query_param_amount (amount),
     519             :     GNUNET_PQ_query_param_end
     520             :   };
     521             : 
     522           0 :   if (NULL == token)
     523           0 :     memset (&tok, 0, sizeof (tok));
     524             :   else
     525           0 :     tok = *token;
     526           0 :   check_connection (pg);
     527           0 :   postgres_preflight (pg);
     528           0 :   qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
     529             :                                            "payment_insert",
     530             :                                            params);
     531           0 :   switch (qs)
     532             :   {
     533           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     534           0 :     GNUNET_break (0);
     535           0 :     return SYNC_DB_SOFT_ERROR;
     536           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     537           0 :     GNUNET_break (0);
     538           0 :     return SYNC_DB_NO_RESULTS;
     539           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     540           0 :     return SYNC_DB_ONE_RESULT;
     541           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     542           0 :     GNUNET_break (0);
     543           0 :     return SYNC_DB_HARD_ERROR;
     544           0 :   default:
     545           0 :     GNUNET_break (0);
     546           0 :     return SYNC_DB_HARD_ERROR;
     547             :   }
     548             : }
     549             : 
     550             : 
     551             : /**
     552             :  * Closure for #payment_by_account_cb.
     553             :  */
     554             : struct PaymentIteratorContext
     555             : {
     556             :   /**
     557             :    * Function to call on each result
     558             :    */
     559             :   SYNC_DB_PaymentPendingIterator it;
     560             : 
     561             :   /**
     562             :    * Closure for @e it.
     563             :    */
     564             :   void *it_cls;
     565             : 
     566             :   /**
     567             :    * Plugin context.
     568             :    */
     569             :   struct PostgresClosure *pg;
     570             : 
     571             :   /**
     572             :    * Query status to return.
     573             :    */
     574             :   enum GNUNET_DB_QueryStatus qs;
     575             : 
     576             : };
     577             : 
     578             : 
     579             : /**
     580             :  * Helper function for #postgres_lookup_pending_payments_by_account().
     581             :  * To be called with the results of a SELECT statement
     582             :  * that has returned @a num_results results.
     583             :  *
     584             :  * @param cls closure of type `struct PaymentIteratorContext *`
     585             :  * @param result the postgres result
     586             :  * @param num_result the number of results in @a result
     587             :  */
     588             : static void
     589           0 : payment_by_account_cb (void *cls,
     590             :                        PGresult *result,
     591             :                        unsigned int num_results)
     592             : {
     593           0 :   struct PaymentIteratorContext *pic = cls;
     594             : 
     595           0 :   for (unsigned int i = 0; i < num_results; i++)
     596             :   {
     597             :     struct GNUNET_TIME_Timestamp timestamp;
     598             :     char *order_id;
     599             :     struct TALER_Amount amount;
     600             :     struct TALER_ClaimTokenP token;
     601           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
     602           0 :       GNUNET_PQ_result_spec_timestamp ("timestamp",
     603             :                                        &timestamp),
     604           0 :       GNUNET_PQ_result_spec_string ("order_id",
     605             :                                     &order_id),
     606           0 :       GNUNET_PQ_result_spec_auto_from_type ("token",
     607             :                                             &token),
     608           0 :       TALER_PQ_result_spec_amount ("amount",
     609           0 :                                    pic->pg->currency,
     610             :                                    &amount),
     611             :       GNUNET_PQ_result_spec_end
     612             :     };
     613             : 
     614           0 :     if (GNUNET_OK !=
     615           0 :         GNUNET_PQ_extract_result (result,
     616             :                                   rs,
     617             :                                   i))
     618             :     {
     619           0 :       GNUNET_break (0);
     620           0 :       pic->qs = GNUNET_DB_STATUS_HARD_ERROR;
     621           0 :       return;
     622             :     }
     623           0 :     pic->qs = i + 1;
     624           0 :     pic->it (pic->it_cls,
     625             :              timestamp,
     626             :              order_id,
     627             :              &token,
     628             :              &amount);
     629           0 :     GNUNET_PQ_cleanup_result (rs);
     630             :   }
     631             : }
     632             : 
     633             : 
     634             : /**
     635             :  * Lookup pending payments by account.
     636             :  *
     637             :  * @param cls closure
     638             :  * @param account_pub account to look for pending payments under
     639             :  * @param it iterator to call on all pending payments
     640             :  * @param it_cls closure for @a it
     641             :  * @return transaction status
     642             :  */
     643             : static enum GNUNET_DB_QueryStatus
     644           0 : postgres_lookup_pending_payments_by_account (void *cls,
     645             :                                              const struct
     646             :                                              SYNC_AccountPublicKeyP *account_pub,
     647             :                                              SYNC_DB_PaymentPendingIterator it,
     648             :                                              void *it_cls)
     649             : {
     650           0 :   struct PostgresClosure *pg = cls;
     651           0 :   struct GNUNET_PQ_QueryParam params[] = {
     652           0 :     GNUNET_PQ_query_param_auto_from_type (account_pub),
     653             :     GNUNET_PQ_query_param_end
     654             :   };
     655           0 :   struct PaymentIteratorContext pic = {
     656             :     .it = it,
     657             :     .it_cls = it_cls,
     658             :     .pg = pg
     659             :   };
     660             :   enum GNUNET_DB_QueryStatus qs;
     661             : 
     662           0 :   check_connection (pg);
     663           0 :   postgres_preflight (pg);
     664           0 :   qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
     665             :                                              "payments_select_by_account",
     666             :                                              params,
     667             :                                              &payment_by_account_cb,
     668             :                                              &pic);
     669           0 :   if (qs > 0)
     670           0 :     return pic.qs;
     671           0 :   GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
     672           0 :   return qs;
     673             : }
     674             : 
     675             : 
     676             : /**
     677             :  * Store backup. Only applicable for the FIRST backup under
     678             :  * an @a account_pub. Use @e update_backup_TR to update an
     679             :  * existing backup.
     680             :  *
     681             :  * @param cls closure
     682             :  * @param account_pub account to store @a backup under
     683             :  * @param account_sig signature affirming storage request
     684             :  * @param backup_hash hash of @a backup
     685             :  * @param backup_size number of bytes in @a backup
     686             :  * @param backup raw data to backup
     687             :  * @return transaction status
     688             :  */
     689             : static enum SYNC_DB_QueryStatus
     690           0 : postgres_store_backup (void *cls,
     691             :                        const struct SYNC_AccountPublicKeyP *account_pub,
     692             :                        const struct SYNC_AccountSignatureP *account_sig,
     693             :                        const struct GNUNET_HashCode *backup_hash,
     694             :                        size_t backup_size,
     695             :                        const void *backup)
     696             : {
     697           0 :   struct PostgresClosure *pg = cls;
     698             :   enum GNUNET_DB_QueryStatus qs;
     699             :   struct GNUNET_HashCode bh;
     700             :   static struct GNUNET_HashCode no_previous_hash;
     701             : 
     702           0 :   check_connection (pg);
     703           0 :   postgres_preflight (pg);
     704             :   {
     705           0 :     struct GNUNET_PQ_QueryParam params[] = {
     706           0 :       GNUNET_PQ_query_param_auto_from_type (account_pub),
     707           0 :       GNUNET_PQ_query_param_auto_from_type (account_sig),
     708           0 :       GNUNET_PQ_query_param_auto_from_type (&no_previous_hash),
     709           0 :       GNUNET_PQ_query_param_auto_from_type (backup_hash),
     710           0 :       GNUNET_PQ_query_param_fixed_size (backup,
     711             :                                         backup_size),
     712             :       GNUNET_PQ_query_param_end
     713             :     };
     714             : 
     715           0 :     qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
     716             :                                              "backup_insert",
     717             :                                              params);
     718             :   }
     719           0 :   switch (qs)
     720             :   {
     721           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     722           0 :     GNUNET_break (0);
     723           0 :     return SYNC_DB_SOFT_ERROR;
     724           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     725           0 :     GNUNET_break (0);
     726           0 :     return SYNC_DB_NO_RESULTS;
     727           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     728           0 :     return SYNC_DB_ONE_RESULT;
     729           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     730             :     /* handle interesting case below */
     731           0 :     break;
     732           0 :   default:
     733           0 :     GNUNET_break (0);
     734           0 :     return SYNC_DB_HARD_ERROR;
     735             :   }
     736             : 
     737             :   /* First, check if account exists */
     738             :   {
     739             :     struct GNUNET_TIME_Timestamp ed;
     740           0 :     struct GNUNET_PQ_QueryParam params[] = {
     741           0 :       GNUNET_PQ_query_param_auto_from_type (account_pub),
     742             :       GNUNET_PQ_query_param_end
     743             :     };
     744           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
     745           0 :       GNUNET_PQ_result_spec_auto_from_type ("expiration_date",
     746             :                                             &ed),
     747             :       GNUNET_PQ_result_spec_end
     748             :     };
     749             : 
     750           0 :     qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     751             :                                                    "account_select",
     752             :                                                    params,
     753             :                                                    rs);
     754             :   }
     755           0 :   switch (qs)
     756             :   {
     757           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     758           0 :     return SYNC_DB_HARD_ERROR;
     759           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     760           0 :     GNUNET_break (0);
     761           0 :     return SYNC_DB_SOFT_ERROR;
     762           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     763           0 :     return SYNC_DB_PAYMENT_REQUIRED;
     764           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     765             :     /* handle interesting case below */
     766           0 :     break;
     767           0 :   default:
     768           0 :     GNUNET_break (0);
     769           0 :     return SYNC_DB_HARD_ERROR;
     770             :   }
     771             : 
     772             :   /* account exists, check if existing backup conflicts */
     773             :   {
     774           0 :     struct GNUNET_PQ_QueryParam params[] = {
     775           0 :       GNUNET_PQ_query_param_auto_from_type (account_pub),
     776             :       GNUNET_PQ_query_param_end
     777             :     };
     778           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
     779           0 :       GNUNET_PQ_result_spec_auto_from_type ("backup_hash",
     780             :                                             &bh),
     781             :       GNUNET_PQ_result_spec_end
     782             :     };
     783             : 
     784           0 :     qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     785             :                                                    "backup_select_hash",
     786             :                                                    params,
     787             :                                                    rs);
     788             :   }
     789           0 :   switch (qs)
     790             :   {
     791           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     792           0 :     return SYNC_DB_HARD_ERROR;
     793           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     794           0 :     GNUNET_break (0);
     795           0 :     return SYNC_DB_SOFT_ERROR;
     796           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     797             :     /* original error must have been a hard error, oddly enough */
     798           0 :     return SYNC_DB_HARD_ERROR;
     799           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     800             :     /* handle interesting case below */
     801           0 :     break;
     802           0 :   default:
     803           0 :     GNUNET_break (0);
     804           0 :     return SYNC_DB_HARD_ERROR;
     805             :   }
     806             : 
     807             :   /* had an existing backup, is it identical? */
     808           0 :   if (0 != GNUNET_memcmp (&bh,
     809             :                           backup_hash))
     810             :     /* previous conflicting backup exists */
     811           0 :     return SYNC_DB_OLD_BACKUP_MISMATCH;
     812             :   /* backup identical to what was provided, no change */
     813           0 :   return SYNC_DB_NO_RESULTS;
     814             : }
     815             : 
     816             : 
     817             : /**
     818             :  * Update backup.
     819             :  *
     820             :  * @param cls closure
     821             :  * @param account_pub account to store @a backup under
     822             :  * @param account_sig signature affirming storage request
     823             :  * @param old_backup_hash hash of the previous backup (must match)
     824             :  * @param backup_hash hash of @a backup
     825             :  * @param backup_size number of bytes in @a backup
     826             :  * @param backup raw data to backup
     827             :  * @return transaction status
     828             :  */
     829             : static enum SYNC_DB_QueryStatus
     830           0 : postgres_update_backup (void *cls,
     831             :                         const struct SYNC_AccountPublicKeyP *account_pub,
     832             :                         const struct GNUNET_HashCode *old_backup_hash,
     833             :                         const struct SYNC_AccountSignatureP *account_sig,
     834             :                         const struct GNUNET_HashCode *backup_hash,
     835             :                         size_t backup_size,
     836             :                         const void *backup)
     837             : {
     838           0 :   struct PostgresClosure *pg = cls;
     839             :   enum GNUNET_DB_QueryStatus qs;
     840             :   struct GNUNET_HashCode bh;
     841             : 
     842           0 :   check_connection (pg);
     843           0 :   postgres_preflight (pg);
     844             :   {
     845           0 :     struct GNUNET_PQ_QueryParam params[] = {
     846           0 :       GNUNET_PQ_query_param_auto_from_type (backup_hash),
     847           0 :       GNUNET_PQ_query_param_auto_from_type (account_sig),
     848           0 :       GNUNET_PQ_query_param_auto_from_type (old_backup_hash),
     849           0 :       GNUNET_PQ_query_param_fixed_size (backup,
     850             :                                         backup_size),
     851           0 :       GNUNET_PQ_query_param_auto_from_type (account_pub),
     852           0 :       GNUNET_PQ_query_param_auto_from_type (old_backup_hash),
     853             :       GNUNET_PQ_query_param_end
     854             :     };
     855             : 
     856           0 :     qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
     857             :                                              "backup_update",
     858             :                                              params);
     859             :   }
     860           0 :   switch (qs)
     861             :   {
     862           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     863           0 :     GNUNET_break (0);
     864           0 :     return SYNC_DB_SOFT_ERROR;
     865           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     866             :     /* handle interesting case below */
     867           0 :     break;
     868           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     869           0 :     return SYNC_DB_ONE_RESULT;
     870           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     871           0 :     GNUNET_break (0);
     872           0 :     return SYNC_DB_HARD_ERROR;
     873           0 :   default:
     874           0 :     GNUNET_break (0);
     875           0 :     return SYNC_DB_HARD_ERROR;
     876             :   }
     877             : 
     878             :   /* First, check if account exists */
     879             :   {
     880             :     struct GNUNET_TIME_Timestamp ed;
     881           0 :     struct GNUNET_PQ_QueryParam params[] = {
     882           0 :       GNUNET_PQ_query_param_auto_from_type (account_pub),
     883             :       GNUNET_PQ_query_param_end
     884             :     };
     885           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
     886           0 :       GNUNET_PQ_result_spec_auto_from_type ("expiration_date",
     887             :                                             &ed),
     888             :       GNUNET_PQ_result_spec_end
     889             :     };
     890             : 
     891           0 :     qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     892             :                                                    "account_select",
     893             :                                                    params,
     894             :                                                    rs);
     895             :   }
     896           0 :   switch (qs)
     897             :   {
     898           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     899           0 :     return SYNC_DB_HARD_ERROR;
     900           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     901           0 :     GNUNET_break (0);
     902           0 :     return SYNC_DB_SOFT_ERROR;
     903           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     904           0 :     return SYNC_DB_PAYMENT_REQUIRED;
     905           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     906             :     /* handle interesting case below */
     907           0 :     break;
     908           0 :   default:
     909           0 :     GNUNET_break (0);
     910           0 :     return SYNC_DB_HARD_ERROR;
     911             :   }
     912             : 
     913             :   /* account exists, check if existing backup conflicts */
     914             :   {
     915           0 :     struct GNUNET_PQ_QueryParam params[] = {
     916           0 :       GNUNET_PQ_query_param_auto_from_type (account_pub),
     917             :       GNUNET_PQ_query_param_end
     918             :     };
     919           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
     920           0 :       GNUNET_PQ_result_spec_auto_from_type ("backup_hash",
     921             :                                             &bh),
     922             :       GNUNET_PQ_result_spec_end
     923             :     };
     924             : 
     925           0 :     qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     926             :                                                    "backup_select_hash",
     927             :                                                    params,
     928             :                                                    rs);
     929             :   }
     930           0 :   switch (qs)
     931             :   {
     932           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     933           0 :     return SYNC_DB_HARD_ERROR;
     934           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     935           0 :     GNUNET_break (0);
     936           0 :     return SYNC_DB_SOFT_ERROR;
     937           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     938           0 :     return SYNC_DB_OLD_BACKUP_MISSING;
     939           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     940             :     /* handle interesting case below */
     941           0 :     break;
     942           0 :   default:
     943           0 :     GNUNET_break (0);
     944           0 :     return SYNC_DB_HARD_ERROR;
     945             :   }
     946             : 
     947             :   /* had an existing backup, is it identical? */
     948           0 :   if (0 == GNUNET_memcmp (&bh,
     949             :                           backup_hash))
     950             :   {
     951             :     /* backup identical to what was provided, no change */
     952           0 :     return SYNC_DB_NO_RESULTS;
     953             :   }
     954           0 :   if (0 == GNUNET_memcmp (&bh,
     955             :                           old_backup_hash))
     956             :     /* all constraints seem satisfied, original error must
     957             :        have been a hard error */
     958           0 :     return SYNC_DB_HARD_ERROR;
     959             :   /* previous backup does not match old_backup_hash */
     960           0 :   return SYNC_DB_OLD_BACKUP_MISMATCH;
     961             : }
     962             : 
     963             : 
     964             : /**
     965             :  * Lookup an account and associated backup meta data.
     966             :  *
     967             :  * @param cls closure
     968             :  * @param account_pub account to store @a backup under
     969             :  * @param backup_hash[OUT] set to hash of @a backup
     970             :  * @return transaction status
     971             :  */
     972             : static enum SYNC_DB_QueryStatus
     973           0 : postgres_lookup_account (void *cls,
     974             :                          const struct SYNC_AccountPublicKeyP *account_pub,
     975             :                          struct GNUNET_HashCode *backup_hash)
     976             : {
     977           0 :   struct PostgresClosure *pg = cls;
     978             :   enum GNUNET_DB_QueryStatus qs;
     979           0 :   struct GNUNET_PQ_QueryParam params[] = {
     980           0 :     GNUNET_PQ_query_param_auto_from_type (account_pub),
     981             :     GNUNET_PQ_query_param_end
     982             :   };
     983             : 
     984           0 :   check_connection (pg);
     985           0 :   postgres_preflight (pg);
     986             :   {
     987           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
     988           0 :       GNUNET_PQ_result_spec_auto_from_type ("backup_hash",
     989             :                                             backup_hash),
     990             :       GNUNET_PQ_result_spec_end
     991             :     };
     992             : 
     993           0 :     qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
     994             :                                                    "backup_select_hash",
     995             :                                                    params,
     996             :                                                    rs);
     997             :   }
     998           0 :   switch (qs)
     999             :   {
    1000           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    1001           0 :     return SYNC_DB_HARD_ERROR;
    1002           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
    1003           0 :     GNUNET_break (0);
    1004           0 :     return SYNC_DB_SOFT_ERROR;
    1005           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    1006           0 :     break; /* handle interesting case below */
    1007           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    1008           0 :     return SYNC_DB_ONE_RESULT;
    1009           0 :   default:
    1010           0 :     GNUNET_break (0);
    1011           0 :     return SYNC_DB_HARD_ERROR;
    1012             :   }
    1013             : 
    1014             :   /* check if account exists */
    1015             :   {
    1016             :     struct GNUNET_TIME_Timestamp expiration;
    1017           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
    1018           0 :       GNUNET_PQ_result_spec_auto_from_type ("expiration_date",
    1019             :                                             &expiration),
    1020             :       GNUNET_PQ_result_spec_end
    1021             :     };
    1022             : 
    1023           0 :     qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
    1024             :                                                    "account_select",
    1025             :                                                    params,
    1026             :                                                    rs);
    1027             :   }
    1028           0 :   switch (qs)
    1029             :   {
    1030           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    1031           0 :     return SYNC_DB_HARD_ERROR;
    1032           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
    1033           0 :     GNUNET_break (0);
    1034           0 :     return SYNC_DB_SOFT_ERROR;
    1035           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    1036             :     /* indicates: no account */
    1037           0 :     return SYNC_DB_PAYMENT_REQUIRED;
    1038           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    1039             :     /* indicates: no backup */
    1040           0 :     return SYNC_DB_NO_RESULTS;
    1041           0 :   default:
    1042           0 :     GNUNET_break (0);
    1043           0 :     return SYNC_DB_HARD_ERROR;
    1044             :   }
    1045             : }
    1046             : 
    1047             : 
    1048             : /**
    1049             :  * Obtain backup.
    1050             :  *
    1051             :  * @param cls closure
    1052             :  * @param account_pub account to store @a backup under
    1053             :  * @param account_sig[OUT] set to signature affirming storage request
    1054             :  * @param prev_hash[OUT] set to hash of previous @a backup, all zeros if none
    1055             :  * @param backup_hash[OUT] set to hash of @a backup
    1056             :  * @param backup_size[OUT] set to number of bytes in @a backup
    1057             :  * @param backup[OUT] set to raw data to backup, caller MUST FREE
    1058             :  */
    1059             : static enum SYNC_DB_QueryStatus
    1060           0 : postgres_lookup_backup (void *cls,
    1061             :                         const struct SYNC_AccountPublicKeyP *account_pub,
    1062             :                         struct SYNC_AccountSignatureP *account_sig,
    1063             :                         struct GNUNET_HashCode *prev_hash,
    1064             :                         struct GNUNET_HashCode *backup_hash,
    1065             :                         size_t *backup_size,
    1066             :                         void **backup)
    1067             : {
    1068           0 :   struct PostgresClosure *pg = cls;
    1069             :   enum GNUNET_DB_QueryStatus qs;
    1070           0 :   struct GNUNET_PQ_QueryParam params[] = {
    1071           0 :     GNUNET_PQ_query_param_auto_from_type (account_pub),
    1072             :     GNUNET_PQ_query_param_end
    1073             :   };
    1074           0 :   struct GNUNET_PQ_ResultSpec rs[] = {
    1075           0 :     GNUNET_PQ_result_spec_auto_from_type ("account_sig",
    1076             :                                           account_sig),
    1077           0 :     GNUNET_PQ_result_spec_auto_from_type ("prev_hash",
    1078             :                                           prev_hash),
    1079           0 :     GNUNET_PQ_result_spec_auto_from_type ("backup_hash",
    1080             :                                           backup_hash),
    1081           0 :     GNUNET_PQ_result_spec_variable_size ("data",
    1082             :                                          backup,
    1083             :                                          backup_size),
    1084             :     GNUNET_PQ_result_spec_end
    1085             :   };
    1086             : 
    1087           0 :   check_connection (pg);
    1088           0 :   postgres_preflight (pg);
    1089           0 :   qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
    1090             :                                                  "backup_select",
    1091             :                                                  params,
    1092             :                                                  rs);
    1093           0 :   switch (qs)
    1094             :   {
    1095           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    1096           0 :     return SYNC_DB_HARD_ERROR;
    1097           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
    1098           0 :     GNUNET_break (0);
    1099           0 :     return SYNC_DB_SOFT_ERROR;
    1100           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    1101           0 :     return SYNC_DB_NO_RESULTS;
    1102           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    1103           0 :     return SYNC_DB_ONE_RESULT;
    1104           0 :   default:
    1105           0 :     GNUNET_break (0);
    1106           0 :     return SYNC_DB_HARD_ERROR;
    1107             :   }
    1108             : }
    1109             : 
    1110             : 
    1111             : /**
    1112             :  * Increment account lifetime.
    1113             :  *
    1114             :  * @param cls closure
    1115             :  * @param account_pub which account received a payment
    1116             :  * @param order_id order which was paid, must be unique and match pending payment
    1117             :  * @param lifetime for how long is the account now paid (increment)
    1118             :  * @return transaction status
    1119             :  */
    1120             : static enum SYNC_DB_QueryStatus
    1121           0 : postgres_increment_lifetime (void *cls,
    1122             :                              const struct SYNC_AccountPublicKeyP *account_pub,
    1123             :                              const char *order_id,
    1124             :                              struct GNUNET_TIME_Relative lifetime)
    1125             : {
    1126           0 :   struct PostgresClosure *pg = cls;
    1127             :   struct GNUNET_TIME_Timestamp expiration;
    1128             :   enum GNUNET_DB_QueryStatus qs;
    1129             : 
    1130           0 :   check_connection (pg);
    1131           0 :   if (GNUNET_OK !=
    1132           0 :       begin_transaction (pg,
    1133             :                          "increment lifetime"))
    1134             :   {
    1135           0 :     GNUNET_break (0);
    1136           0 :     return SYNC_DB_HARD_ERROR;
    1137             :   }
    1138             : 
    1139             :   {
    1140           0 :     struct GNUNET_PQ_QueryParam params[] = {
    1141           0 :       GNUNET_PQ_query_param_string (order_id),
    1142           0 :       GNUNET_PQ_query_param_auto_from_type (account_pub),
    1143             :       GNUNET_PQ_query_param_end
    1144             :     };
    1145             : 
    1146           0 :     qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
    1147             :                                              "payment_done",
    1148             :                                              params);
    1149           0 :     switch (qs)
    1150             :     {
    1151           0 :     case GNUNET_DB_STATUS_HARD_ERROR:
    1152           0 :       GNUNET_break (0);
    1153           0 :       rollback (pg);
    1154           0 :       return SYNC_DB_HARD_ERROR;
    1155           0 :     case GNUNET_DB_STATUS_SOFT_ERROR:
    1156           0 :       GNUNET_break (0);
    1157           0 :       rollback (pg);
    1158           0 :       return SYNC_DB_SOFT_ERROR;
    1159           0 :     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    1160           0 :       rollback (pg);
    1161           0 :       return SYNC_DB_NO_RESULTS;
    1162           0 :     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    1163           0 :       break;
    1164             :     }
    1165           0 :   }
    1166             : 
    1167             :   {
    1168           0 :     struct GNUNET_PQ_QueryParam params[] = {
    1169           0 :       GNUNET_PQ_query_param_auto_from_type (account_pub),
    1170             :       GNUNET_PQ_query_param_end
    1171             :     };
    1172           0 :     struct GNUNET_PQ_ResultSpec rs[] = {
    1173           0 :       GNUNET_PQ_result_spec_timestamp ("expiration_date",
    1174             :                                        &expiration),
    1175             :       GNUNET_PQ_result_spec_end
    1176             :     };
    1177             : 
    1178           0 :     qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
    1179             :                                                    "account_select",
    1180             :                                                    params,
    1181             :                                                    rs);
    1182             :   }
    1183             : 
    1184           0 :   switch (qs)
    1185             :   {
    1186           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    1187           0 :     rollback (pg);
    1188           0 :     return SYNC_DB_HARD_ERROR;
    1189           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
    1190           0 :     rollback (pg);
    1191           0 :     return SYNC_DB_SOFT_ERROR;
    1192           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    1193             :     {
    1194           0 :       struct GNUNET_PQ_QueryParam params[] = {
    1195           0 :         GNUNET_PQ_query_param_auto_from_type (account_pub),
    1196           0 :         GNUNET_PQ_query_param_timestamp (&expiration),
    1197             :         GNUNET_PQ_query_param_end
    1198             :       };
    1199             : 
    1200           0 :       expiration = GNUNET_TIME_relative_to_timestamp (lifetime);
    1201           0 :       qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
    1202             :                                                "account_insert",
    1203             :                                                params);
    1204             :     }
    1205           0 :     break;
    1206           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    1207             :     {
    1208           0 :       struct GNUNET_PQ_QueryParam params[] = {
    1209           0 :         GNUNET_PQ_query_param_timestamp (&expiration),
    1210           0 :         GNUNET_PQ_query_param_auto_from_type (account_pub),
    1211             :         GNUNET_PQ_query_param_end
    1212             :       };
    1213             : 
    1214           0 :       expiration = GNUNET_TIME_absolute_to_timestamp (
    1215             :         GNUNET_TIME_absolute_add (expiration.abs_time,
    1216             :                                   lifetime));
    1217           0 :       qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
    1218             :                                                "account_update",
    1219             :                                                params);
    1220             :     }
    1221           0 :     break;
    1222           0 :   default:
    1223           0 :     GNUNET_break (0);
    1224           0 :     return SYNC_DB_HARD_ERROR;
    1225             :   }
    1226           0 :   switch (qs)
    1227             :   {
    1228           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    1229           0 :     rollback (pg);
    1230           0 :     return SYNC_DB_HARD_ERROR;
    1231           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
    1232           0 :     rollback (pg);
    1233           0 :     GNUNET_break (0);
    1234           0 :     return SYNC_DB_SOFT_ERROR;
    1235           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    1236           0 :     GNUNET_break (0);
    1237           0 :     rollback (pg);
    1238           0 :     return SYNC_DB_NO_RESULTS;
    1239           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    1240           0 :     break;
    1241           0 :   default:
    1242           0 :     GNUNET_break (0);
    1243           0 :     return SYNC_DB_HARD_ERROR;
    1244             :   }
    1245           0 :   qs = commit_transaction (pg);
    1246           0 :   switch (qs)
    1247             :   {
    1248           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    1249           0 :     return SYNC_DB_HARD_ERROR;
    1250           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
    1251           0 :     GNUNET_break (0);
    1252           0 :     return SYNC_DB_SOFT_ERROR;
    1253           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    1254           0 :     return SYNC_DB_ONE_RESULT;
    1255           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    1256           0 :     return SYNC_DB_ONE_RESULT;
    1257           0 :   default:
    1258           0 :     GNUNET_break (0);
    1259           0 :     return SYNC_DB_HARD_ERROR;
    1260             :   }
    1261             : }
    1262             : 
    1263             : 
    1264             : /**
    1265             :  * Initialize tables.
    1266             :  *
    1267             :  * @param cls the `struct PostgresClosure` with the plugin-specific state
    1268             :  * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
    1269             :  */
    1270             : static enum GNUNET_GenericReturnValue
    1271           0 : postgres_create_tables (void *cls)
    1272             : {
    1273           0 :   struct PostgresClosure *pc = cls;
    1274             :   struct GNUNET_PQ_Context *conn;
    1275             : 
    1276           0 :   conn = GNUNET_PQ_connect_with_cfg (pc->cfg,
    1277             :                                      "syncdb-postgres",
    1278             :                                      "sync-",
    1279             :                                      NULL,
    1280             :                                      NULL);
    1281           0 :   if (NULL == conn)
    1282           0 :     return GNUNET_SYSERR;
    1283           0 :   GNUNET_PQ_disconnect (conn);
    1284           0 :   return GNUNET_OK;
    1285             : }
    1286             : 
    1287             : 
    1288             : /**
    1289             :  * Initialize Postgres database subsystem.
    1290             :  *
    1291             :  * @param cls a configuration instance
    1292             :  * @return NULL on error, otherwise a `struct TALER_SYNCDB_Plugin`
    1293             :  */
    1294             : void *
    1295           1 : libsync_plugin_db_postgres_init (void *cls)
    1296             : {
    1297           1 :   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
    1298             :   struct PostgresClosure *pg;
    1299             :   struct SYNC_DatabasePlugin *plugin;
    1300             : 
    1301           1 :   pg = GNUNET_new (struct PostgresClosure);
    1302           1 :   pg->cfg = cfg;
    1303           1 :   if (GNUNET_OK !=
    1304           1 :       GNUNET_CONFIGURATION_get_value_filename (cfg,
    1305             :                                                "syncdb-postgres",
    1306             :                                                "SQL_DIR",
    1307             :                                                &pg->sql_dir))
    1308             :   {
    1309           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1310             :                                "syncdb-postgres",
    1311             :                                "SQL_DIR");
    1312           0 :     GNUNET_free (pg);
    1313           0 :     return NULL;
    1314             :   }
    1315           1 :   if (GNUNET_OK !=
    1316           1 :       GNUNET_CONFIGURATION_get_value_string (cfg,
    1317             :                                              "taler",
    1318             :                                              "CURRENCY",
    1319             :                                              &pg->currency))
    1320             :   {
    1321           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1322             :                                "taler",
    1323             :                                "CURRENCY");
    1324           0 :     GNUNET_free (pg->sql_dir);
    1325           0 :     GNUNET_free (pg);
    1326           0 :     return NULL;
    1327             :   }
    1328           1 :   if (GNUNET_OK !=
    1329           1 :       internal_setup (pg,
    1330             :                       true))
    1331             :   {
    1332           1 :     GNUNET_free (pg->currency);
    1333           1 :     GNUNET_free (pg->sql_dir);
    1334           1 :     GNUNET_free (pg);
    1335           1 :     return NULL;
    1336             :   }
    1337           0 :   plugin = GNUNET_new (struct SYNC_DatabasePlugin);
    1338           0 :   plugin->cls = pg;
    1339           0 :   plugin->create_tables = &postgres_create_tables;
    1340           0 :   plugin->drop_tables = &postgres_drop_tables;
    1341           0 :   plugin->preflight = &postgres_preflight;
    1342           0 :   plugin->gc = &postgres_gc;
    1343           0 :   plugin->store_payment_TR = &postgres_store_payment;
    1344           0 :   plugin->lookup_pending_payments_by_account_TR =
    1345             :     &postgres_lookup_pending_payments_by_account;
    1346           0 :   plugin->store_backup_TR = &postgres_store_backup;
    1347           0 :   plugin->lookup_account_TR = &postgres_lookup_account;
    1348           0 :   plugin->lookup_backup_TR = &postgres_lookup_backup;
    1349           0 :   plugin->update_backup_TR = &postgres_update_backup;
    1350           0 :   plugin->increment_lifetime_TR = &postgres_increment_lifetime;
    1351           0 :   return plugin;
    1352             : }
    1353             : 
    1354             : 
    1355             : /**
    1356             :  * Shutdown Postgres database subsystem.
    1357             :  *
    1358             :  * @param cls a `struct SYNC_DB_Plugin`
    1359             :  * @return NULL (always)
    1360             :  */
    1361             : void *
    1362           0 : libsync_plugin_db_postgres_done (void *cls)
    1363             : {
    1364           0 :   struct SYNC_DatabasePlugin *plugin = cls;
    1365           0 :   struct PostgresClosure *pg = plugin->cls;
    1366             : 
    1367           0 :   GNUNET_PQ_disconnect (pg->conn);
    1368           0 :   GNUNET_free (pg->currency);
    1369           0 :   GNUNET_free (pg->sql_dir);
    1370           0 :   GNUNET_free (pg);
    1371           0 :   GNUNET_free (plugin);
    1372           0 :   return NULL;
    1373             : }
    1374             : 
    1375             : 
    1376             : /* end of plugin_syncdb_postgres.c */

Generated by: LCOV version 1.14