LCOV - code coverage report
Current view: top level - syncdb - plugin_syncdb_postgres.c (source / functions) Hit Total Coverage
Test: GNU Taler coverage report Lines: 29 444 6.5 %
Date: 2020-10-21 06:15:51 Functions: 1 17 5.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14