exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

pg_lookup_records_by_table.c (115382B)


      1 /*
      2    This file is part of GNUnet
      3    Copyright (C) 2020-2025 Taler Systems SA
      4 
      5    GNUnet is free software: you can redistribute it and/or modify it
      6    under the terms of the GNU Affero General Public License as published
      7    by the Free Software Foundation, either version 3 of the License,
      8    or (at your option) any later version.
      9 
     10    GNUnet is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13    Affero General Public License for more details.
     14 
     15    You should have received a copy of the GNU Affero General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18      SPDX-License-Identifier: AGPL3.0-or-later
     19  */
     20 /**
     21  * @file exchangedb/pg_lookup_records_by_table.c
     22  * @brief implementation of lookup_records_by_table
     23  * @author Christian Grothoff
     24  * @author Özgür Kesim
     25  */
     26 #include "taler/platform.h"
     27 #include "taler/taler_error_codes.h"
     28 #include "taler/taler_dbevents.h"
     29 #include "taler/taler_pq_lib.h"
     30 #include "pg_lookup_records_by_table.h"
     31 #include "pg_helper.h"
     32 #include <gnunet/gnunet_pq_lib.h>
     33 
     34 
     35 /**
     36  * Closure for callbacks used by #postgres_lookup_records_by_table.
     37  */
     38 struct LookupRecordsByTableContext
     39 {
     40   /**
     41    * Plugin context.
     42    */
     43   struct PostgresClosure *pg;
     44 
     45   /**
     46    * Function to call with the results.
     47    */
     48   TALER_EXCHANGEDB_ReplicationCallback cb;
     49 
     50   /**
     51    * Closure for @a cb.
     52    */
     53   void *cb_cls;
     54 
     55   /**
     56    * Set to true on errors.
     57    */
     58   bool error;
     59 };
     60 
     61 
     62 /**
     63  * Function called with denominations table entries.
     64  *
     65  * @param cls closure
     66  * @param result the postgres result
     67  * @param num_results the number of results in @a result
     68  */
     69 static void
     70 lrbt_cb_table_denominations (void *cls,
     71                              PGresult *result,
     72                              unsigned int num_results)
     73 {
     74   struct LookupRecordsByTableContext *ctx = cls;
     75   struct PostgresClosure *pg = ctx->pg;
     76   struct TALER_EXCHANGEDB_TableData td = {
     77     .table = TALER_EXCHANGEDB_RT_DENOMINATIONS
     78   };
     79 
     80   for (unsigned int i = 0; i<num_results; i++)
     81   {
     82     struct GNUNET_PQ_ResultSpec rs[] = {
     83       GNUNET_PQ_result_spec_uint64 (
     84         "serial",
     85         &td.serial),
     86       GNUNET_PQ_result_spec_uint32 (
     87         "denom_type",
     88         &td.details.denominations.denom_type),
     89       GNUNET_PQ_result_spec_uint32 (
     90         "age_mask",
     91         &td.details.denominations.age_mask),
     92       TALER_PQ_result_spec_denom_pub (
     93         "denom_pub",
     94         &td.details.denominations.denom_pub),
     95       GNUNET_PQ_result_spec_auto_from_type (
     96         "master_sig",
     97         &td.details.denominations.master_sig),
     98       GNUNET_PQ_result_spec_timestamp (
     99         "valid_from",
    100         &td.details.denominations.valid_from),
    101       GNUNET_PQ_result_spec_timestamp (
    102         "expire_withdraw",
    103         &td.details.denominations.
    104         expire_withdraw),
    105       GNUNET_PQ_result_spec_timestamp (
    106         "expire_deposit",
    107         &td.details.denominations.
    108         expire_deposit),
    109       GNUNET_PQ_result_spec_timestamp (
    110         "expire_legal",
    111         &td.details.denominations.expire_legal),
    112       TALER_PQ_RESULT_SPEC_AMOUNT (
    113         "coin",
    114         &td.details.denominations.coin),
    115       TALER_PQ_RESULT_SPEC_AMOUNT (
    116         "fee_withdraw",
    117         &td.details.denominations.fees.withdraw),
    118       TALER_PQ_RESULT_SPEC_AMOUNT (
    119         "fee_deposit",
    120         &td.details.denominations.fees.deposit),
    121       TALER_PQ_RESULT_SPEC_AMOUNT (
    122         "fee_refresh",
    123         &td.details.denominations.fees.refresh),
    124       TALER_PQ_RESULT_SPEC_AMOUNT (
    125         "fee_refund",
    126         &td.details.denominations.fees.refund),
    127       GNUNET_PQ_result_spec_end
    128     };
    129 
    130     if (GNUNET_OK !=
    131         GNUNET_PQ_extract_result (result,
    132                                   rs,
    133                                   i))
    134     {
    135       GNUNET_break (0);
    136       ctx->error = true;
    137       return;
    138     }
    139     ctx->cb (ctx->cb_cls,
    140              &td);
    141     GNUNET_PQ_cleanup_result (rs);
    142   }
    143 }
    144 
    145 
    146 /**
    147  * Function called with denomination_revocations table entries.
    148  *
    149  * @param cls closure
    150  * @param result the postgres result
    151  * @param num_results the number of results in @a result
    152  */
    153 static void
    154 lrbt_cb_table_denomination_revocations (void *cls,
    155                                         PGresult *result,
    156                                         unsigned int num_results)
    157 {
    158   struct LookupRecordsByTableContext *ctx = cls;
    159   struct TALER_EXCHANGEDB_TableData td = {
    160     .table = TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS
    161   };
    162 
    163   for (unsigned int i = 0; i<num_results; i++)
    164   {
    165     struct GNUNET_PQ_ResultSpec rs[] = {
    166       GNUNET_PQ_result_spec_uint64 ("serial",
    167                                     &td.serial),
    168       GNUNET_PQ_result_spec_uint64 (
    169         "denominations_serial",
    170         &td.details.denomination_revocations.denominations_serial),
    171       GNUNET_PQ_result_spec_auto_from_type (
    172         "master_sig",
    173         &td.details.denomination_revocations.master_sig),
    174       GNUNET_PQ_result_spec_end
    175     };
    176 
    177     if (GNUNET_OK !=
    178         GNUNET_PQ_extract_result (result,
    179                                   rs,
    180                                   i))
    181     {
    182       GNUNET_break (0);
    183       ctx->error = true;
    184       return;
    185     }
    186     ctx->cb (ctx->cb_cls,
    187              &td);
    188     GNUNET_PQ_cleanup_result (rs);
    189   }
    190 }
    191 
    192 
    193 /**
    194  * Function called with wire_targets table entries.
    195  *
    196  * @param cls closure
    197  * @param result the postgres result
    198  * @param num_results the number of results in @a result
    199  */
    200 static void
    201 lrbt_cb_table_wire_targets (void *cls,
    202                             PGresult *result,
    203                             unsigned int num_results)
    204 {
    205   struct LookupRecordsByTableContext *ctx = cls;
    206   struct TALER_EXCHANGEDB_TableData td = {
    207     .table = TALER_EXCHANGEDB_RT_WIRE_TARGETS
    208   };
    209 
    210   for (unsigned int i = 0; i<num_results; i++)
    211   {
    212     struct GNUNET_PQ_ResultSpec rs[] = {
    213       GNUNET_PQ_result_spec_uint64 (
    214         "serial",
    215         &td.serial),
    216       GNUNET_PQ_result_spec_string (
    217         "payto_uri",
    218         &td.details.wire_targets.full_payto_uri.full_payto),
    219       GNUNET_PQ_result_spec_end
    220     };
    221 
    222     if (GNUNET_OK !=
    223         GNUNET_PQ_extract_result (result,
    224                                   rs,
    225                                   i))
    226     {
    227       GNUNET_break (0);
    228       ctx->error = true;
    229       return;
    230     }
    231     ctx->cb (ctx->cb_cls,
    232              &td);
    233     GNUNET_PQ_cleanup_result (rs);
    234   }
    235 }
    236 
    237 
    238 /**
    239  * Function called with wire_targets table entries.
    240  *
    241  * @param cls closure
    242  * @param result the postgres result
    243  * @param num_results the number of results in @a result
    244  */
    245 static void
    246 lrbt_cb_table_kyc_targets (void *cls,
    247                            PGresult *result,
    248                            unsigned int num_results)
    249 {
    250   struct LookupRecordsByTableContext *ctx = cls;
    251   struct TALER_EXCHANGEDB_TableData td = {
    252     .table = TALER_EXCHANGEDB_RT_KYC_TARGETS
    253   };
    254 
    255   for (unsigned int i = 0; i<num_results; i++)
    256   {
    257     struct GNUNET_PQ_ResultSpec rs[] = {
    258       GNUNET_PQ_result_spec_uint64 (
    259         "serial",
    260         &td.serial),
    261       GNUNET_PQ_result_spec_auto_from_type (
    262         "h_normalized_payto",
    263         &td.details.kyc_targets.h_normalized_payto),
    264       GNUNET_PQ_result_spec_auto_from_type (
    265         "access_token",
    266         &td.details.kyc_targets.access_token),
    267       GNUNET_PQ_result_spec_allow_null (
    268         GNUNET_PQ_result_spec_auto_from_type (
    269           "target_pub",
    270           &td.details.kyc_targets.target_pub),
    271         &td.details.kyc_targets.no_account),
    272       GNUNET_PQ_result_spec_bool (
    273         "is_wallet",
    274         &td.details.kyc_targets.is_wallet),
    275       GNUNET_PQ_result_spec_end
    276     };
    277 
    278     if (GNUNET_OK !=
    279         GNUNET_PQ_extract_result (result,
    280                                   rs,
    281                                   i))
    282     {
    283       GNUNET_break (0);
    284       ctx->error = true;
    285       return;
    286     }
    287     ctx->cb (ctx->cb_cls,
    288              &td);
    289     GNUNET_PQ_cleanup_result (rs);
    290   }
    291 }
    292 
    293 
    294 /**
    295  * Function called with reserves table entries.
    296  *
    297  * @param cls closure
    298  * @param result the postgres result
    299  * @param num_results the number of results in @a result
    300  */
    301 static void
    302 lrbt_cb_table_reserves (void *cls,
    303                         PGresult *result,
    304                         unsigned int num_results)
    305 {
    306   struct LookupRecordsByTableContext *ctx = cls;
    307   struct TALER_EXCHANGEDB_TableData td = {
    308     .table = TALER_EXCHANGEDB_RT_RESERVES
    309   };
    310 
    311   for (unsigned int i = 0; i<num_results; i++)
    312   {
    313     struct GNUNET_PQ_ResultSpec rs[] = {
    314       GNUNET_PQ_result_spec_uint64 ("serial",
    315                                     &td.serial),
    316       GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
    317                                             &td.details.reserves.reserve_pub),
    318       GNUNET_PQ_result_spec_timestamp ("expiration_date",
    319                                        &td.details.reserves.expiration_date),
    320       GNUNET_PQ_result_spec_timestamp ("gc_date",
    321                                        &td.details.reserves.gc_date),
    322       GNUNET_PQ_result_spec_end
    323     };
    324 
    325     if (GNUNET_OK !=
    326         GNUNET_PQ_extract_result (result,
    327                                   rs,
    328                                   i))
    329     {
    330       GNUNET_break (0);
    331       ctx->error = true;
    332       return;
    333     }
    334     ctx->cb (ctx->cb_cls,
    335              &td);
    336     GNUNET_PQ_cleanup_result (rs);
    337   }
    338 }
    339 
    340 
    341 /**
    342  * Function called with reserves_in table entries.
    343  *
    344  * @param cls closure
    345  * @param result the postgres result
    346  * @param num_results the number of results in @a result
    347  */
    348 static void
    349 lrbt_cb_table_reserves_in (void *cls,
    350                            PGresult *result,
    351                            unsigned int num_results)
    352 {
    353   struct LookupRecordsByTableContext *ctx = cls;
    354   struct PostgresClosure *pg = ctx->pg;
    355   struct TALER_EXCHANGEDB_TableData td = {
    356     .table = TALER_EXCHANGEDB_RT_RESERVES_IN
    357   };
    358 
    359   for (unsigned int i = 0; i<num_results; i++)
    360   {
    361     struct GNUNET_PQ_ResultSpec rs[] = {
    362       GNUNET_PQ_result_spec_uint64 (
    363         "serial",
    364         &td.serial),
    365       GNUNET_PQ_result_spec_auto_from_type (
    366         "reserve_pub",
    367         &td.details.reserves_in.reserve_pub),
    368       GNUNET_PQ_result_spec_uint64 (
    369         "wire_reference",
    370         &td.details.reserves_in.wire_reference),
    371       TALER_PQ_RESULT_SPEC_AMOUNT (
    372         "credit",
    373         &td.details.reserves_in.credit),
    374       GNUNET_PQ_result_spec_auto_from_type (
    375         "wire_source_h_payto",
    376         &td.details.reserves_in.sender_account_h_payto),
    377       GNUNET_PQ_result_spec_string (
    378         "exchange_account_section",
    379         &td.details.reserves_in.exchange_account_section),
    380       GNUNET_PQ_result_spec_timestamp (
    381         "execution_date",
    382         &td.details.reserves_in.execution_date),
    383       GNUNET_PQ_result_spec_end
    384     };
    385 
    386     if (GNUNET_OK !=
    387         GNUNET_PQ_extract_result (result,
    388                                   rs,
    389                                   i))
    390     {
    391       GNUNET_break (0);
    392       ctx->error = true;
    393       return;
    394     }
    395     ctx->cb (ctx->cb_cls,
    396              &td);
    397     GNUNET_PQ_cleanup_result (rs);
    398   }
    399 }
    400 
    401 
    402 /**
    403  * Function called with kycauth_in table entries.
    404  *
    405  * @param cls closure
    406  * @param result the postgres result
    407  * @param num_results the number of results in @a result
    408  */
    409 static void
    410 lrbt_cb_table_kycauth_in (void *cls,
    411                           PGresult *result,
    412                           unsigned int num_results)
    413 {
    414   struct LookupRecordsByTableContext *ctx = cls;
    415   struct PostgresClosure *pg = ctx->pg;
    416   struct TALER_EXCHANGEDB_TableData td = {
    417     .table = TALER_EXCHANGEDB_RT_KYCAUTHS_IN
    418   };
    419 
    420   for (unsigned int i = 0; i<num_results; i++)
    421   {
    422     struct GNUNET_PQ_ResultSpec rs[] = {
    423       GNUNET_PQ_result_spec_uint64 (
    424         "serial",
    425         &td.serial),
    426       GNUNET_PQ_result_spec_auto_from_type (
    427         "account_pub",
    428         &td.details.kycauth_in.account_pub),
    429       GNUNET_PQ_result_spec_uint64 (
    430         "wire_reference",
    431         &td.details.kycauth_in.wire_reference),
    432       TALER_PQ_RESULT_SPEC_AMOUNT (
    433         "credit",
    434         &td.details.kycauth_in.credit),
    435       GNUNET_PQ_result_spec_auto_from_type (
    436         "wire_source_h_payto",
    437         &td.details.kycauth_in.sender_account_h_payto),
    438       GNUNET_PQ_result_spec_string (
    439         "exchange_account_section",
    440         &td.details.kycauth_in.exchange_account_section),
    441       GNUNET_PQ_result_spec_timestamp (
    442         "execution_date",
    443         &td.details.kycauth_in.execution_date),
    444       GNUNET_PQ_result_spec_end
    445     };
    446 
    447     if (GNUNET_OK !=
    448         GNUNET_PQ_extract_result (result,
    449                                   rs,
    450                                   i))
    451     {
    452       GNUNET_break (0);
    453       ctx->error = true;
    454       return;
    455     }
    456     ctx->cb (ctx->cb_cls,
    457              &td);
    458     GNUNET_PQ_cleanup_result (rs);
    459   }
    460 }
    461 
    462 
    463 /**
    464  * Function called with reserves_close table entries.
    465  *
    466  * @param cls closure
    467  * @param result the postgres result
    468  * @param num_results the number of results in @a result
    469  */
    470 static void
    471 lrbt_cb_table_reserves_close (void *cls,
    472                               PGresult *result,
    473                               unsigned int num_results)
    474 {
    475   struct LookupRecordsByTableContext *ctx = cls;
    476   struct PostgresClosure *pg = ctx->pg;
    477   struct TALER_EXCHANGEDB_TableData td = {
    478     .table = TALER_EXCHANGEDB_RT_RESERVES_CLOSE
    479   };
    480 
    481   for (unsigned int i = 0; i<num_results; i++)
    482   {
    483     struct GNUNET_PQ_ResultSpec rs[] = {
    484       GNUNET_PQ_result_spec_uint64 (
    485         "serial",
    486         &td.serial),
    487       GNUNET_PQ_result_spec_auto_from_type (
    488         "reserve_pub",
    489         &td.details.reserves_close.reserve_pub),
    490       GNUNET_PQ_result_spec_timestamp (
    491         "execution_date",
    492         &td.details.reserves_close.execution_date),
    493       GNUNET_PQ_result_spec_auto_from_type (
    494         "wtid",
    495         &td.details.reserves_close.wtid),
    496       GNUNET_PQ_result_spec_auto_from_type (
    497         "wire_target_h_payto",
    498         &td.details.reserves_close.sender_account_h_payto),
    499       TALER_PQ_RESULT_SPEC_AMOUNT (
    500         "amount",
    501         &td.details.reserves_close.amount),
    502       TALER_PQ_RESULT_SPEC_AMOUNT (
    503         "closing_fee",
    504         &td.details.reserves_close.closing_fee),
    505       GNUNET_PQ_result_spec_end
    506     };
    507 
    508     if (GNUNET_OK !=
    509         GNUNET_PQ_extract_result (result,
    510                                   rs,
    511                                   i))
    512     {
    513       GNUNET_break (0);
    514       ctx->error = true;
    515       return;
    516     }
    517     ctx->cb (ctx->cb_cls,
    518              &td);
    519     GNUNET_PQ_cleanup_result (rs);
    520   }
    521 }
    522 
    523 
    524 /**
    525  * Function called with reserves_open_requests table entries.
    526  *
    527  * @param cls closure
    528  * @param result the postgres result
    529  * @param num_results the number of results in @a result
    530  */
    531 static void
    532 lrbt_cb_table_reserves_open_requests (void *cls,
    533                                       PGresult *result,
    534                                       unsigned int num_results)
    535 {
    536   struct LookupRecordsByTableContext *ctx = cls;
    537   struct PostgresClosure *pg = ctx->pg;
    538   struct TALER_EXCHANGEDB_TableData td = {
    539     .table = TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS
    540   };
    541 
    542   for (unsigned int i = 0; i<num_results; i++)
    543   {
    544     struct GNUNET_PQ_ResultSpec rs[] = {
    545       GNUNET_PQ_result_spec_uint64 ("serial",
    546                                     &td.serial),
    547       GNUNET_PQ_result_spec_auto_from_type (
    548         "reserve_pub",
    549         &td.details.reserves_open_requests.reserve_pub),
    550       GNUNET_PQ_result_spec_timestamp (
    551         "request_timestamp",
    552         &td.details.reserves_open_requests.request_timestamp),
    553       GNUNET_PQ_result_spec_timestamp (
    554         "expiration_date",
    555         &td.details.reserves_open_requests.expiration_date),
    556       GNUNET_PQ_result_spec_auto_from_type (
    557         "reserve_sig",
    558         &td.details.reserves_open_requests.reserve_sig),
    559       TALER_PQ_RESULT_SPEC_AMOUNT (
    560         "reserve_payment",
    561         &td.details.reserves_open_requests.reserve_payment),
    562       GNUNET_PQ_result_spec_uint32 (
    563         "requested_purse_limit",
    564         &td.details.reserves_open_requests.requested_purse_limit),
    565       GNUNET_PQ_result_spec_end
    566     };
    567 
    568     if (GNUNET_OK !=
    569         GNUNET_PQ_extract_result (result,
    570                                   rs,
    571                                   i))
    572     {
    573       GNUNET_break (0);
    574       ctx->error = true;
    575       return;
    576     }
    577     ctx->cb (ctx->cb_cls,
    578              &td);
    579     GNUNET_PQ_cleanup_result (rs);
    580   }
    581 }
    582 
    583 
    584 /**
    585  * Function called with reserves_open_deposits table entries.
    586  *
    587  * @param cls closure
    588  * @param result the postgres result
    589  * @param num_results the number of results in @a result
    590  */
    591 static void
    592 lrbt_cb_table_reserves_open_deposits (void *cls,
    593                                       PGresult *result,
    594                                       unsigned int num_results)
    595 {
    596   struct LookupRecordsByTableContext *ctx = cls;
    597   struct PostgresClosure *pg = ctx->pg;
    598   struct TALER_EXCHANGEDB_TableData td = {
    599     .table = TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS
    600   };
    601 
    602   for (unsigned int i = 0; i<num_results; i++)
    603   {
    604     struct GNUNET_PQ_ResultSpec rs[] = {
    605       GNUNET_PQ_result_spec_uint64 ("serial",
    606                                     &td.serial),
    607       GNUNET_PQ_result_spec_auto_from_type (
    608         "reserve_sig",
    609         &td.details.reserves_open_deposits.reserve_sig),
    610       GNUNET_PQ_result_spec_auto_from_type (
    611         "reserve_pub",
    612         &td.details.reserves_open_deposits.reserve_pub),
    613       GNUNET_PQ_result_spec_auto_from_type (
    614         "coin_pub",
    615         &td.details.reserves_open_deposits.coin_pub),
    616       GNUNET_PQ_result_spec_auto_from_type (
    617         "coin_sig",
    618         &td.details.reserves_open_deposits.coin_sig),
    619       TALER_PQ_RESULT_SPEC_AMOUNT (
    620         "contribution",
    621         &td.details.reserves_open_deposits.contribution),
    622       GNUNET_PQ_result_spec_end
    623     };
    624 
    625     if (GNUNET_OK !=
    626         GNUNET_PQ_extract_result (result,
    627                                   rs,
    628                                   i))
    629     {
    630       GNUNET_break (0);
    631       ctx->error = true;
    632       return;
    633     }
    634     ctx->cb (ctx->cb_cls,
    635              &td);
    636     GNUNET_PQ_cleanup_result (rs);
    637   }
    638 }
    639 
    640 
    641 /**
    642  * Function called with auditors table entries.
    643  *
    644  * @param cls closure
    645  * @param result the postgres result
    646  * @param num_results the number of results in @a result
    647  */
    648 static void
    649 lrbt_cb_table_auditors (void *cls,
    650                         PGresult *result,
    651                         unsigned int num_results)
    652 {
    653   struct LookupRecordsByTableContext *ctx = cls;
    654   struct TALER_EXCHANGEDB_TableData td = {
    655     .table = TALER_EXCHANGEDB_RT_AUDITORS
    656   };
    657 
    658   for (unsigned int i = 0; i<num_results; i++)
    659   {
    660     struct GNUNET_PQ_ResultSpec rs[] = {
    661       GNUNET_PQ_result_spec_uint64 ("serial",
    662                                     &td.serial),
    663       GNUNET_PQ_result_spec_auto_from_type ("auditor_pub",
    664                                             &td.details.auditors.auditor_pub),
    665       GNUNET_PQ_result_spec_string ("auditor_url",
    666                                     &td.details.auditors.auditor_url),
    667       GNUNET_PQ_result_spec_string ("auditor_name",
    668                                     &td.details.auditors.auditor_name),
    669       GNUNET_PQ_result_spec_bool ("is_active",
    670                                   &td.details.auditors.is_active),
    671       GNUNET_PQ_result_spec_timestamp ("last_change",
    672                                        &td.details.auditors.last_change),
    673       GNUNET_PQ_result_spec_end
    674     };
    675 
    676     if (GNUNET_OK !=
    677         GNUNET_PQ_extract_result (result,
    678                                   rs,
    679                                   i))
    680     {
    681       GNUNET_break (0);
    682       ctx->error = true;
    683       return;
    684     }
    685     ctx->cb (ctx->cb_cls,
    686              &td);
    687     GNUNET_PQ_cleanup_result (rs);
    688   }
    689 }
    690 
    691 
    692 /**
    693  * Function called with auditor_denom_sigs table entries.
    694  *
    695  * @param cls closure
    696  * @param result the postgres result
    697  * @param num_results the number of results in @a result
    698  */
    699 static void
    700 lrbt_cb_table_auditor_denom_sigs (void *cls,
    701                                   PGresult *result,
    702                                   unsigned int num_results)
    703 {
    704   struct LookupRecordsByTableContext *ctx = cls;
    705   struct TALER_EXCHANGEDB_TableData td = {
    706     .table = TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS
    707   };
    708 
    709   for (unsigned int i = 0; i<num_results; i++)
    710   {
    711     struct GNUNET_PQ_ResultSpec rs[] = {
    712       GNUNET_PQ_result_spec_uint64 (
    713         "serial",
    714         &td.serial),
    715       GNUNET_PQ_result_spec_uint64 (
    716         "auditor_uuid",
    717         &td.details.auditor_denom_sigs.auditor_uuid),
    718       GNUNET_PQ_result_spec_uint64 (
    719         "denominations_serial",
    720         &td.details.auditor_denom_sigs.denominations_serial),
    721       GNUNET_PQ_result_spec_auto_from_type (
    722         "auditor_sig",
    723         &td.details.auditor_denom_sigs.auditor_sig),
    724       GNUNET_PQ_result_spec_end
    725     };
    726 
    727     if (GNUNET_OK !=
    728         GNUNET_PQ_extract_result (result,
    729                                   rs,
    730                                   i))
    731     {
    732       GNUNET_break (0);
    733       ctx->error = true;
    734       return;
    735     }
    736     ctx->cb (ctx->cb_cls,
    737              &td);
    738     GNUNET_PQ_cleanup_result (rs);
    739   }
    740 }
    741 
    742 
    743 /**
    744  * Function called with exchange_sign_keys table entries.
    745  *
    746  * @param cls closure
    747  * @param result the postgres result
    748  * @param num_results the number of results in @a result
    749  */
    750 static void
    751 lrbt_cb_table_exchange_sign_keys (void *cls,
    752                                   PGresult *result,
    753                                   unsigned int num_results)
    754 {
    755   struct LookupRecordsByTableContext *ctx = cls;
    756   struct TALER_EXCHANGEDB_TableData td = {
    757     .table = TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS
    758   };
    759 
    760   for (unsigned int i = 0; i<num_results; i++)
    761   {
    762     struct GNUNET_PQ_ResultSpec rs[] = {
    763       GNUNET_PQ_result_spec_uint64 ("serial",
    764                                     &td.serial),
    765       GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
    766                                             &td.details.exchange_sign_keys.
    767                                             exchange_pub),
    768       GNUNET_PQ_result_spec_auto_from_type ("master_sig",
    769                                             &td.details.exchange_sign_keys.
    770                                             master_sig),
    771       GNUNET_PQ_result_spec_timestamp ("valid_from",
    772                                        &td.details.exchange_sign_keys.meta.
    773                                        start),
    774       GNUNET_PQ_result_spec_timestamp ("expire_sign",
    775                                        &td.details.exchange_sign_keys.meta.
    776                                        expire_sign),
    777       GNUNET_PQ_result_spec_timestamp ("expire_legal",
    778                                        &td.details.exchange_sign_keys.meta.
    779                                        expire_legal),
    780       GNUNET_PQ_result_spec_end
    781     };
    782 
    783     if (GNUNET_OK !=
    784         GNUNET_PQ_extract_result (result,
    785                                   rs,
    786                                   i))
    787     {
    788       GNUNET_break (0);
    789       ctx->error = true;
    790       return;
    791     }
    792     ctx->cb (ctx->cb_cls,
    793              &td);
    794     GNUNET_PQ_cleanup_result (rs);
    795   }
    796 }
    797 
    798 
    799 /**
    800  * Function called with signkey_revocations table entries.
    801  *
    802  * @param cls closure
    803  * @param result the postgres result
    804  * @param num_results the number of results in @a result
    805  */
    806 static void
    807 lrbt_cb_table_signkey_revocations (void *cls,
    808                                    PGresult *result,
    809                                    unsigned int num_results)
    810 {
    811   struct LookupRecordsByTableContext *ctx = cls;
    812   struct TALER_EXCHANGEDB_TableData td = {
    813     .table = TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS
    814   };
    815 
    816   for (unsigned int i = 0; i<num_results; i++)
    817   {
    818     struct GNUNET_PQ_ResultSpec rs[] = {
    819       GNUNET_PQ_result_spec_uint64 ("serial",
    820                                     &td.serial),
    821       GNUNET_PQ_result_spec_uint64 ("esk_serial",
    822                                     &td.details.signkey_revocations.esk_serial),
    823       GNUNET_PQ_result_spec_auto_from_type ("master_sig",
    824                                             &td.details.signkey_revocations.
    825                                             master_sig),
    826       GNUNET_PQ_result_spec_end
    827     };
    828 
    829     if (GNUNET_OK !=
    830         GNUNET_PQ_extract_result (result,
    831                                   rs,
    832                                   i))
    833     {
    834       GNUNET_break (0);
    835       ctx->error = true;
    836       return;
    837     }
    838     ctx->cb (ctx->cb_cls,
    839              &td);
    840     GNUNET_PQ_cleanup_result (rs);
    841   }
    842 }
    843 
    844 
    845 /**
    846  * Function called with known_coins table entries.
    847  *
    848  * @param cls closure
    849  * @param result the postgres result
    850  * @param num_results the number of results in @a result
    851  */
    852 static void
    853 lrbt_cb_table_known_coins (void *cls,
    854                            PGresult *result,
    855                            unsigned int num_results)
    856 {
    857   struct LookupRecordsByTableContext *ctx = cls;
    858   struct TALER_EXCHANGEDB_TableData td = {
    859     .table = TALER_EXCHANGEDB_RT_KNOWN_COINS
    860   };
    861 
    862   for (unsigned int i = 0; i<num_results; i++)
    863   {
    864     struct GNUNET_PQ_ResultSpec rs[] = {
    865       GNUNET_PQ_result_spec_uint64 (
    866         "serial",
    867         &td.serial),
    868       GNUNET_PQ_result_spec_auto_from_type (
    869         "coin_pub",
    870         &td.details.known_coins.coin_pub),
    871       TALER_PQ_result_spec_denom_sig (
    872         "denom_sig",
    873         &td.details.known_coins.denom_sig),
    874       GNUNET_PQ_result_spec_uint64 (
    875         "denominations_serial",
    876         &td.details.known_coins.denominations_serial),
    877       GNUNET_PQ_result_spec_end
    878     };
    879 
    880     if (GNUNET_OK !=
    881         GNUNET_PQ_extract_result (result,
    882                                   rs,
    883                                   i))
    884     {
    885       GNUNET_break (0);
    886       ctx->error = true;
    887       return;
    888     }
    889     ctx->cb (ctx->cb_cls,
    890              &td);
    891     GNUNET_PQ_cleanup_result (rs);
    892   }
    893 }
    894 
    895 
    896 /**
    897  * Function called with refresh table entries.
    898  *
    899  * @param cls closure
    900  * @param result the postgres result
    901  * @param num_results the number of results in @a result
    902  */
    903 static void
    904 lrbt_cb_table_refresh (void *cls,
    905                        PGresult *result,
    906                        unsigned int num_results)
    907 {
    908   struct LookupRecordsByTableContext *ctx = cls;
    909   struct PostgresClosure *pg = ctx->pg;
    910   struct TALER_EXCHANGEDB_TableData td = {
    911     .table = TALER_EXCHANGEDB_RT_REFRESH
    912   };
    913 
    914   for (unsigned int i = 0; i<num_results; i++)
    915   {
    916     bool no_cs_r_values;
    917     bool no_cs_r_choices;
    918     size_t num_denom_sigs;
    919     struct GNUNET_PQ_ResultSpec rs[] = {
    920       GNUNET_PQ_result_spec_uint64 (
    921         "serial",
    922         &td.serial),
    923       GNUNET_PQ_result_spec_auto_from_type (
    924         "rc",
    925         &td.details.refresh.rc),
    926       GNUNET_PQ_result_spec_auto_from_type (
    927         "execution_date",
    928         &td.details.refresh.execution_date),
    929       TALER_PQ_RESULT_SPEC_AMOUNT (
    930         "amount_with_fee",
    931         &td.details.refresh.amount_with_fee),
    932       GNUNET_PQ_result_spec_auto_from_type (
    933         "old_coin_pub",
    934         &td.details.refresh.old_coin_pub),
    935       GNUNET_PQ_result_spec_auto_from_type (
    936         "old_coin_sig",
    937         &td.details.refresh.old_coin_sig),
    938       GNUNET_PQ_result_spec_auto_from_type (
    939         "refresh_seed",
    940         &td.details.refresh.refresh_seed),
    941       GNUNET_PQ_result_spec_uint32 (
    942         "noreveal_index",
    943         &td.details.refresh.noreveal_index),
    944       GNUNET_PQ_result_spec_auto_from_type (
    945         "planchets_h",
    946         &td.details.refresh.planchets_h),
    947       GNUNET_PQ_result_spec_auto_from_type (
    948         "selected_h",
    949         &td.details.refresh.selected_h),
    950       GNUNET_PQ_result_spec_allow_null (
    951         GNUNET_PQ_result_spec_auto_from_type (
    952           "blinding_seed",
    953           &td.details.refresh.blinding_seed),
    954         &td.details.refresh.no_blinding_seed),
    955       GNUNET_PQ_result_spec_allow_null (
    956         TALER_PQ_result_spec_array_cs_r_pub (
    957           pg->conn,
    958           "cs_r_values",
    959           &td.details.refresh.num_cs_r_values,
    960           &td.details.refresh.cs_r_values),
    961         &no_cs_r_values),
    962       GNUNET_PQ_result_spec_allow_null (
    963         GNUNET_PQ_result_spec_uint64 (
    964           "cs_r_choices",
    965           &td.details.refresh.cs_r_choices),
    966         &no_cs_r_choices),
    967       GNUNET_PQ_result_spec_array_uint64 (
    968         pg->conn,
    969         "denom_serials",
    970         &td.details.refresh.num_coins,
    971         &td.details.refresh.denom_serials),
    972       TALER_PQ_result_spec_array_blinded_denom_sig (
    973         pg->conn,
    974         "denom_sigs",
    975         &num_denom_sigs,
    976         &td.details.refresh.denom_sigs),
    977       GNUNET_PQ_result_spec_end
    978     };
    979 
    980     if (GNUNET_OK !=
    981         GNUNET_PQ_extract_result (result,
    982                                   rs,
    983                                   i))
    984     {
    985       GNUNET_break (0);
    986       ctx->error = true;
    987       GNUNET_PQ_cleanup_result (rs);
    988       return;
    989     }
    990     ctx->cb (ctx->cb_cls,
    991              &td);
    992     GNUNET_PQ_cleanup_result (rs);
    993   }
    994 }
    995 
    996 
    997 /**
    998  * Function called with batch deposits table entries.
    999  *
   1000  * @param cls closure
   1001  * @param result the postgres result
   1002  * @param num_results the number of results in @a result
   1003  */
   1004 static void
   1005 lrbt_cb_table_batch_deposits (void *cls,
   1006                               PGresult *result,
   1007                               unsigned int num_results)
   1008 {
   1009   struct LookupRecordsByTableContext *ctx = cls;
   1010   struct PostgresClosure *pg = ctx->pg;
   1011   struct TALER_EXCHANGEDB_TableData td = {
   1012     .table = TALER_EXCHANGEDB_RT_BATCH_DEPOSITS
   1013   };
   1014 
   1015   for (unsigned int i = 0; i<num_results; i++)
   1016   {
   1017     struct GNUNET_PQ_ResultSpec rs[] = {
   1018       GNUNET_PQ_result_spec_uint64 (
   1019         "serial",
   1020         &td.serial),
   1021       GNUNET_PQ_result_spec_uint64 (
   1022         "shard",
   1023         &td.details.batch_deposits.shard),
   1024       GNUNET_PQ_result_spec_auto_from_type (
   1025         "merchant_pub",
   1026         &td.details.batch_deposits.merchant_pub),
   1027       GNUNET_PQ_result_spec_timestamp (
   1028         "wallet_timestamp",
   1029         &td.details.batch_deposits.wallet_timestamp),
   1030       GNUNET_PQ_result_spec_timestamp (
   1031         "exchange_timestamp",
   1032         &td.details.batch_deposits.exchange_timestamp),
   1033       GNUNET_PQ_result_spec_timestamp (
   1034         "refund_deadline",
   1035         &td.details.batch_deposits.refund_deadline),
   1036       GNUNET_PQ_result_spec_timestamp (
   1037         "wire_deadline",
   1038         &td.details.batch_deposits.wire_deadline),
   1039       GNUNET_PQ_result_spec_auto_from_type (
   1040         "h_contract_terms",
   1041         &td.details.batch_deposits.h_contract_terms),
   1042       GNUNET_PQ_result_spec_allow_null (
   1043         GNUNET_PQ_result_spec_auto_from_type (
   1044           "wallet_data_hash",
   1045           &td.details.batch_deposits.wallet_data_hash),
   1046         &td.details.batch_deposits.no_wallet_data_hash),
   1047       GNUNET_PQ_result_spec_auto_from_type (
   1048         "wire_salt",
   1049         &td.details.batch_deposits.wire_salt),
   1050       GNUNET_PQ_result_spec_auto_from_type (
   1051         "wire_target_h_payto",
   1052         &td.details.batch_deposits.wire_target_h_payto),
   1053       GNUNET_PQ_result_spec_allow_null (
   1054         GNUNET_PQ_result_spec_uint64 (
   1055           "policy_details_serial_id",
   1056           &td.details.batch_deposits.policy_details_serial_id),
   1057         &td.details.batch_deposits.no_policy_details),
   1058       GNUNET_PQ_result_spec_bool (
   1059         "policy_blocked",
   1060         &td.details.batch_deposits.policy_blocked),
   1061       TALER_PQ_RESULT_SPEC_AMOUNT (
   1062         "total_amount",
   1063         &td.details.batch_deposits.total_amount),
   1064       TALER_PQ_RESULT_SPEC_AMOUNT (
   1065         "total_without_fee",
   1066         &td.details.batch_deposits.total_without_fee),
   1067       GNUNET_PQ_result_spec_auto_from_type (
   1068         "merchant_sig",
   1069         &td.details.batch_deposits.merchant_sig),
   1070       GNUNET_PQ_result_spec_bool (
   1071         "done",
   1072         &td.details.batch_deposits.done),
   1073       GNUNET_PQ_result_spec_end
   1074     };
   1075 
   1076     td.details.batch_deposits.policy_details_serial_id = 0;
   1077     if (GNUNET_OK !=
   1078         GNUNET_PQ_extract_result (result,
   1079                                   rs,
   1080                                   i))
   1081     {
   1082       GNUNET_break (0);
   1083       ctx->error = true;
   1084       return;
   1085     }
   1086     ctx->cb (ctx->cb_cls,
   1087              &td);
   1088     GNUNET_PQ_cleanup_result (rs);
   1089   }
   1090 }
   1091 
   1092 
   1093 /**
   1094  * Function called with coin deposits table entries.
   1095  *
   1096  * @param cls closure
   1097  * @param result the postgres result
   1098  * @param num_results the number of results in @a result
   1099  */
   1100 static void
   1101 lrbt_cb_table_coin_deposits (void *cls,
   1102                              PGresult *result,
   1103                              unsigned int num_results)
   1104 {
   1105   struct LookupRecordsByTableContext *ctx = cls;
   1106   struct PostgresClosure *pg = ctx->pg;
   1107   struct TALER_EXCHANGEDB_TableData td = {
   1108     .table = TALER_EXCHANGEDB_RT_COIN_DEPOSITS
   1109   };
   1110 
   1111   for (unsigned int i = 0; i<num_results; i++)
   1112   {
   1113     struct GNUNET_PQ_ResultSpec rs[] = {
   1114       GNUNET_PQ_result_spec_uint64 (
   1115         "serial",
   1116         &td.serial),
   1117       GNUNET_PQ_result_spec_uint64 (
   1118         "batch_deposit_serial_id",
   1119         &td.details.coin_deposits.batch_deposit_serial_id),
   1120       GNUNET_PQ_result_spec_auto_from_type (
   1121         "coin_pub",
   1122         &td.details.coin_deposits.coin_pub),
   1123       GNUNET_PQ_result_spec_auto_from_type (
   1124         "coin_sig",
   1125         &td.details.coin_deposits.coin_sig),
   1126       TALER_PQ_RESULT_SPEC_AMOUNT (
   1127         "amount_with_fee",
   1128         &td.details.coin_deposits.amount_with_fee),
   1129       GNUNET_PQ_result_spec_end
   1130     };
   1131 
   1132     if (GNUNET_OK !=
   1133         GNUNET_PQ_extract_result (result,
   1134                                   rs,
   1135                                   i))
   1136     {
   1137       GNUNET_break (0);
   1138       ctx->error = true;
   1139       return;
   1140     }
   1141     ctx->cb (ctx->cb_cls,
   1142              &td);
   1143     GNUNET_PQ_cleanup_result (rs);
   1144   }
   1145 }
   1146 
   1147 
   1148 /**
   1149  * Function called with refunds table entries.
   1150  *
   1151  * @param cls closure
   1152  * @param result the postgres result
   1153  * @param num_results the number of results in @a result
   1154  */
   1155 static void
   1156 lrbt_cb_table_refunds (void *cls,
   1157                        PGresult *result,
   1158                        unsigned int num_results)
   1159 {
   1160   struct LookupRecordsByTableContext *ctx = cls;
   1161   struct PostgresClosure *pg = ctx->pg;
   1162   struct TALER_EXCHANGEDB_TableData td = {
   1163     .table = TALER_EXCHANGEDB_RT_REFUNDS
   1164   };
   1165 
   1166   for (unsigned int i = 0; i<num_results; i++)
   1167   {
   1168     struct GNUNET_PQ_ResultSpec rs[] = {
   1169       GNUNET_PQ_result_spec_uint64 (
   1170         "serial",
   1171         &td.serial),
   1172       GNUNET_PQ_result_spec_auto_from_type (
   1173         "coin_pub",
   1174         &td.details.refunds.coin_pub),
   1175       GNUNET_PQ_result_spec_auto_from_type (
   1176         "merchant_sig",
   1177         &td.details.refunds.merchant_sig),
   1178       GNUNET_PQ_result_spec_uint64 (
   1179         "rtransaction_id",
   1180         &td.details.refunds.rtransaction_id),
   1181       TALER_PQ_RESULT_SPEC_AMOUNT (
   1182         "amount_with_fee",
   1183         &td.details.refunds.amount_with_fee),
   1184       GNUNET_PQ_result_spec_uint64 (
   1185         "batch_deposit_serial_id",
   1186         &td.details.refunds.batch_deposit_serial_id),
   1187       GNUNET_PQ_result_spec_end
   1188     };
   1189 
   1190     if (GNUNET_OK !=
   1191         GNUNET_PQ_extract_result (result,
   1192                                   rs,
   1193                                   i))
   1194     {
   1195       GNUNET_break (0);
   1196       ctx->error = true;
   1197       return;
   1198     }
   1199     ctx->cb (ctx->cb_cls,
   1200              &td);
   1201     GNUNET_PQ_cleanup_result (rs);
   1202   }
   1203 }
   1204 
   1205 
   1206 /**
   1207  * Function called with wire_out table entries.
   1208  *
   1209  * @param cls closure
   1210  * @param result the postgres result
   1211  * @param num_results the number of results in @a result
   1212  */
   1213 static void
   1214 lrbt_cb_table_wire_out (void *cls,
   1215                         PGresult *result,
   1216                         unsigned int num_results)
   1217 {
   1218   struct LookupRecordsByTableContext *ctx = cls;
   1219   struct PostgresClosure *pg = ctx->pg;
   1220   struct TALER_EXCHANGEDB_TableData td = {
   1221     .table = TALER_EXCHANGEDB_RT_WIRE_OUT
   1222   };
   1223 
   1224   for (unsigned int i = 0; i<num_results; i++)
   1225   {
   1226     struct GNUNET_PQ_ResultSpec rs[] = {
   1227       GNUNET_PQ_result_spec_uint64 ("serial",
   1228                                     &td.serial),
   1229       GNUNET_PQ_result_spec_timestamp (
   1230         "execution_date",
   1231         &td.details.wire_out.execution_date),
   1232       GNUNET_PQ_result_spec_auto_from_type (
   1233         "wtid_raw",
   1234         &td.details.wire_out.wtid_raw),
   1235       GNUNET_PQ_result_spec_auto_from_type (
   1236         "wire_target_h_payto",
   1237         &td.details.wire_out.wire_target_h_payto),
   1238       GNUNET_PQ_result_spec_string (
   1239         "exchange_account_section",
   1240         &td.details.wire_out.exchange_account_section),
   1241       TALER_PQ_RESULT_SPEC_AMOUNT (
   1242         "amount",
   1243         &td.details.wire_out.amount),
   1244       GNUNET_PQ_result_spec_end
   1245     };
   1246 
   1247     if (GNUNET_OK !=
   1248         GNUNET_PQ_extract_result (result,
   1249                                   rs,
   1250                                   i))
   1251     {
   1252       GNUNET_break (0);
   1253       ctx->error = true;
   1254       return;
   1255     }
   1256     ctx->cb (ctx->cb_cls,
   1257              &td);
   1258     GNUNET_PQ_cleanup_result (rs);
   1259   }
   1260 }
   1261 
   1262 
   1263 /**
   1264  * Function called with aggregation_tracking table entries.
   1265  *
   1266  * @param cls closure
   1267  * @param result the postgres result
   1268  * @param num_results the number of results in @a result
   1269  */
   1270 static void
   1271 lrbt_cb_table_aggregation_tracking (void *cls,
   1272                                     PGresult *result,
   1273                                     unsigned int num_results)
   1274 {
   1275   struct LookupRecordsByTableContext *ctx = cls;
   1276   struct TALER_EXCHANGEDB_TableData td = {
   1277     .table = TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING
   1278   };
   1279 
   1280   for (unsigned int i = 0; i<num_results; i++)
   1281   {
   1282     struct GNUNET_PQ_ResultSpec rs[] = {
   1283       GNUNET_PQ_result_spec_uint64 (
   1284         "serial",
   1285         &td.serial),
   1286       GNUNET_PQ_result_spec_uint64 (
   1287         "batch_deposit_serial_id",
   1288         &td.details.aggregation_tracking.batch_deposit_serial_id),
   1289       GNUNET_PQ_result_spec_auto_from_type (
   1290         "wtid_raw",
   1291         &td.details.aggregation_tracking.wtid_raw),
   1292       GNUNET_PQ_result_spec_end
   1293     };
   1294 
   1295     if (GNUNET_OK !=
   1296         GNUNET_PQ_extract_result (result,
   1297                                   rs,
   1298                                   i))
   1299     {
   1300       GNUNET_break (0);
   1301       ctx->error = true;
   1302       return;
   1303     }
   1304     ctx->cb (ctx->cb_cls,
   1305              &td);
   1306     GNUNET_PQ_cleanup_result (rs);
   1307   }
   1308 }
   1309 
   1310 
   1311 /**
   1312  * Function called with wire_fee table entries.
   1313  *
   1314  * @param cls closure
   1315  * @param result the postgres result
   1316  * @param num_results the number of results in @a result
   1317  */
   1318 static void
   1319 lrbt_cb_table_wire_fee (void *cls,
   1320                         PGresult *result,
   1321                         unsigned int num_results)
   1322 {
   1323   struct LookupRecordsByTableContext *ctx = cls;
   1324   struct PostgresClosure *pg = ctx->pg;
   1325   struct TALER_EXCHANGEDB_TableData td = {
   1326     .table = TALER_EXCHANGEDB_RT_WIRE_FEE
   1327   };
   1328 
   1329   for (unsigned int i = 0; i<num_results; i++)
   1330   {
   1331     struct GNUNET_PQ_ResultSpec rs[] = {
   1332       GNUNET_PQ_result_spec_uint64 ("serial",
   1333                                     &td.serial),
   1334       GNUNET_PQ_result_spec_string ("wire_method",
   1335                                     &td.details.wire_fee.wire_method),
   1336       GNUNET_PQ_result_spec_timestamp ("start_date",
   1337                                        &td.details.wire_fee.start_date),
   1338       GNUNET_PQ_result_spec_timestamp ("end_date",
   1339                                        &td.details.wire_fee.end_date),
   1340       TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
   1341                                    &td.details.wire_fee.fees.wire),
   1342       TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
   1343                                    &td.details.wire_fee.fees.closing),
   1344       GNUNET_PQ_result_spec_auto_from_type ("master_sig",
   1345                                             &td.details.wire_fee.master_sig),
   1346       GNUNET_PQ_result_spec_end
   1347     };
   1348 
   1349     if (GNUNET_OK !=
   1350         GNUNET_PQ_extract_result (result,
   1351                                   rs,
   1352                                   i))
   1353     {
   1354       GNUNET_break (0);
   1355       ctx->error = true;
   1356       return;
   1357     }
   1358     ctx->cb (ctx->cb_cls,
   1359              &td);
   1360     GNUNET_PQ_cleanup_result (rs);
   1361   }
   1362 }
   1363 
   1364 
   1365 /**
   1366  * Function called with wire_fee table entries.
   1367  *
   1368  * @param cls closure
   1369  * @param result the postgres result
   1370  * @param num_results the number of results in @a result
   1371  */
   1372 static void
   1373 lrbt_cb_table_global_fee (void *cls,
   1374                           PGresult *result,
   1375                           unsigned int num_results)
   1376 {
   1377   struct LookupRecordsByTableContext *ctx = cls;
   1378   struct PostgresClosure *pg = ctx->pg;
   1379   struct TALER_EXCHANGEDB_TableData td = {
   1380     .table = TALER_EXCHANGEDB_RT_GLOBAL_FEE
   1381   };
   1382 
   1383   for (unsigned int i = 0; i<num_results; i++)
   1384   {
   1385     struct GNUNET_PQ_ResultSpec rs[] = {
   1386       GNUNET_PQ_result_spec_uint64 (
   1387         "serial",
   1388         &td.serial),
   1389       GNUNET_PQ_result_spec_timestamp (
   1390         "start_date",
   1391         &td.details.global_fee.start_date),
   1392       GNUNET_PQ_result_spec_timestamp (
   1393         "end_date",
   1394         &td.details.global_fee.end_date),
   1395       TALER_PQ_RESULT_SPEC_AMOUNT (
   1396         "history_fee",
   1397         &td.details.global_fee.fees.history),
   1398       TALER_PQ_RESULT_SPEC_AMOUNT (
   1399         "account_fee",
   1400         &td.details.global_fee.fees.account),
   1401       TALER_PQ_RESULT_SPEC_AMOUNT (
   1402         "purse_fee",
   1403         &td.details.global_fee.fees.purse),
   1404       GNUNET_PQ_result_spec_relative_time (
   1405         "purse_timeout",
   1406         &td.details.global_fee.purse_timeout),
   1407       GNUNET_PQ_result_spec_relative_time (
   1408         "history_expiration",
   1409         &td.details.global_fee.history_expiration),
   1410       GNUNET_PQ_result_spec_uint32 (
   1411         "purse_account_limit",
   1412         &td.details.global_fee.purse_account_limit),
   1413       GNUNET_PQ_result_spec_auto_from_type (
   1414         "master_sig",
   1415         &td.details.global_fee.master_sig),
   1416       GNUNET_PQ_result_spec_end
   1417     };
   1418 
   1419     if (GNUNET_OK !=
   1420         GNUNET_PQ_extract_result (result,
   1421                                   rs,
   1422                                   i))
   1423     {
   1424       GNUNET_break (0);
   1425       ctx->error = true;
   1426       return;
   1427     }
   1428     ctx->cb (ctx->cb_cls,
   1429              &td);
   1430     GNUNET_PQ_cleanup_result (rs);
   1431   }
   1432 }
   1433 
   1434 
   1435 /**
   1436  * Function called with recoup table entries.
   1437  *
   1438  * @param cls closure
   1439  * @param result the postgres result
   1440  * @param num_results the number of results in @a result
   1441  */
   1442 static void
   1443 lrbt_cb_table_recoup (void *cls,
   1444                       PGresult *result,
   1445                       unsigned int num_results)
   1446 {
   1447   struct LookupRecordsByTableContext *ctx = cls;
   1448   struct PostgresClosure *pg = ctx->pg;
   1449   struct TALER_EXCHANGEDB_TableData td = {
   1450     .table = TALER_EXCHANGEDB_RT_RECOUP
   1451   };
   1452 
   1453   for (unsigned int i = 0; i<num_results; i++)
   1454   {
   1455     struct GNUNET_PQ_ResultSpec rs[] = {
   1456       GNUNET_PQ_result_spec_uint64 ("serial",
   1457                                     &td.serial),
   1458       GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
   1459                                             &td.details.recoup.coin_sig),
   1460       GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
   1461                                             &td.details.recoup.coin_blind),
   1462       TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
   1463                                    &td.details.recoup.amount),
   1464       GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
   1465                                        &td.details.recoup.timestamp),
   1466       GNUNET_PQ_result_spec_auto_from_type (
   1467         "coin_pub",
   1468         &td.details.recoup.coin_pub),
   1469       GNUNET_PQ_result_spec_uint64 ("withdraw_serial_id",
   1470                                     &td.details.recoup.withdraw_serial_id),
   1471       GNUNET_PQ_result_spec_end
   1472     };
   1473 
   1474     if (GNUNET_OK !=
   1475         GNUNET_PQ_extract_result (result,
   1476                                   rs,
   1477                                   i))
   1478     {
   1479       GNUNET_break (0);
   1480       ctx->error = true;
   1481       return;
   1482     }
   1483     ctx->cb (ctx->cb_cls,
   1484              &td);
   1485     GNUNET_PQ_cleanup_result (rs);
   1486   }
   1487 }
   1488 
   1489 
   1490 /**
   1491  * Function called with recoup_refresh table entries.
   1492  *
   1493  * @param cls closure
   1494  * @param result the postgres result
   1495  * @param num_results the number of results in @a result
   1496  */
   1497 static void
   1498 lrbt_cb_table_recoup_refresh (void *cls,
   1499                               PGresult *result,
   1500                               unsigned int num_results)
   1501 {
   1502   struct LookupRecordsByTableContext *ctx = cls;
   1503   struct PostgresClosure *pg = ctx->pg;
   1504   struct TALER_EXCHANGEDB_TableData td = {
   1505     .table = TALER_EXCHANGEDB_RT_RECOUP_REFRESH
   1506   };
   1507 
   1508   for (unsigned int i = 0; i<num_results; i++)
   1509   {
   1510     struct GNUNET_PQ_ResultSpec rs[] = {
   1511       GNUNET_PQ_result_spec_uint64 ("serial",
   1512                                     &td.serial),
   1513       GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
   1514                                             &td.details.recoup_refresh.coin_sig)
   1515       ,
   1516       GNUNET_PQ_result_spec_auto_from_type (
   1517         "coin_blind",
   1518         &td.details.recoup_refresh.coin_blind),
   1519       TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
   1520                                    &td.details.recoup_refresh.amount),
   1521       GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
   1522                                        &td.details.recoup_refresh.timestamp),
   1523       GNUNET_PQ_result_spec_uint64 ("known_coin_id",
   1524                                     &td.details.recoup_refresh.known_coin_id),
   1525       GNUNET_PQ_result_spec_auto_from_type (
   1526         "coin_pub",
   1527         &td.details.recoup_refresh.coin_pub),
   1528       GNUNET_PQ_result_spec_uint64 ("rrc_serial",
   1529                                     &td.details.recoup_refresh.rrc_serial),
   1530       GNUNET_PQ_result_spec_end
   1531     };
   1532 
   1533     if (GNUNET_OK !=
   1534         GNUNET_PQ_extract_result (result,
   1535                                   rs,
   1536                                   i))
   1537     {
   1538       GNUNET_break (0);
   1539       ctx->error = true;
   1540       return;
   1541     }
   1542     ctx->cb (ctx->cb_cls,
   1543              &td);
   1544     GNUNET_PQ_cleanup_result (rs);
   1545   }
   1546 }
   1547 
   1548 
   1549 /**
   1550  * Function called with extensions table entries.
   1551  *
   1552  * @param cls closure
   1553  * @param result the postgres result
   1554  * @param num_results the number of results in @a result
   1555  */
   1556 static void
   1557 lrbt_cb_table_extensions (void *cls,
   1558                           PGresult *result,
   1559                           unsigned int num_results)
   1560 {
   1561   struct LookupRecordsByTableContext *ctx = cls;
   1562   struct TALER_EXCHANGEDB_TableData td = {
   1563     .table = TALER_EXCHANGEDB_RT_EXTENSIONS
   1564   };
   1565   bool no_manifest = false;
   1566 
   1567   for (unsigned int i = 0; i<num_results; i++)
   1568   {
   1569     struct GNUNET_PQ_ResultSpec rs[] = {
   1570       GNUNET_PQ_result_spec_uint64 ("extension_id",
   1571                                     &td.serial),
   1572       GNUNET_PQ_result_spec_string ("name",
   1573                                     &td.details.extensions.name),
   1574       GNUNET_PQ_result_spec_allow_null (
   1575         GNUNET_PQ_result_spec_string ("manifest",
   1576                                       &td.details.extensions.manifest),
   1577         &no_manifest),
   1578       GNUNET_PQ_result_spec_end
   1579     };
   1580 
   1581     if (GNUNET_OK !=
   1582         GNUNET_PQ_extract_result (result,
   1583                                   rs,
   1584                                   i))
   1585     {
   1586       GNUNET_break (0);
   1587       ctx->error = true;
   1588       return;
   1589     }
   1590     ctx->cb (ctx->cb_cls,
   1591              &td);
   1592     GNUNET_PQ_cleanup_result (rs);
   1593   }
   1594 }
   1595 
   1596 
   1597 /**
   1598  * Function called with policy_details table entries.
   1599  *
   1600  * @param cls closure
   1601  * @param result the postgres result
   1602  * @param num_results the number of results in @a result
   1603  */
   1604 static void
   1605 lrbt_cb_table_policy_details (void *cls,
   1606                               PGresult *result,
   1607                               unsigned int num_results)
   1608 {
   1609   struct LookupRecordsByTableContext *ctx = cls;
   1610   struct PostgresClosure *pg = ctx->pg;
   1611   struct TALER_EXCHANGEDB_TableData td = {
   1612     .table = TALER_EXCHANGEDB_RT_POLICY_DETAILS
   1613   };
   1614 
   1615   for (unsigned int i = 0; i<num_results; i++)
   1616   {
   1617     struct GNUNET_PQ_ResultSpec rs[] = {
   1618       GNUNET_PQ_result_spec_uint64 ("policy_details_serial_id",
   1619                                     &td.serial),
   1620       GNUNET_PQ_result_spec_auto_from_type ("hash_code",
   1621                                             &td.details.policy_details.
   1622                                             hash_code),
   1623       GNUNET_PQ_result_spec_allow_null (
   1624         TALER_PQ_result_spec_json ("policy_json",
   1625                                    &td.details.policy_details.
   1626                                    policy_json),
   1627         &td.details.policy_details.no_policy_json),
   1628       GNUNET_PQ_result_spec_timestamp ("deadline",
   1629                                        &td.details.policy_details.
   1630                                        deadline),
   1631       TALER_PQ_RESULT_SPEC_AMOUNT ("commitment",
   1632                                    &td.details.policy_details.
   1633                                    commitment),
   1634       TALER_PQ_RESULT_SPEC_AMOUNT ("accumulated_total",
   1635                                    &td.details.policy_details.
   1636                                    accumulated_total),
   1637       TALER_PQ_RESULT_SPEC_AMOUNT ("fee",
   1638                                    &td.details.policy_details.
   1639                                    fee),
   1640       TALER_PQ_RESULT_SPEC_AMOUNT ("transferable",
   1641                                    &td.details.policy_details.
   1642                                    transferable),
   1643       GNUNET_PQ_result_spec_uint16 ("fulfillment_state",
   1644                                     &td.details.policy_details.
   1645                                     fulfillment_state),
   1646       GNUNET_PQ_result_spec_allow_null (
   1647         GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
   1648                                       &td.details.policy_details.
   1649                                       fulfillment_id),
   1650         &td.details.policy_details.no_fulfillment_id),
   1651       GNUNET_PQ_result_spec_end
   1652     };
   1653 
   1654     if (GNUNET_OK !=
   1655         GNUNET_PQ_extract_result (result,
   1656                                   rs,
   1657                                   i))
   1658     {
   1659       GNUNET_break (0);
   1660       ctx->error = true;
   1661       return;
   1662     }
   1663     ctx->cb (ctx->cb_cls,
   1664              &td);
   1665     GNUNET_PQ_cleanup_result (rs);
   1666   }
   1667 }
   1668 
   1669 
   1670 /**
   1671  * Function called with policy_fulfillments table entries.
   1672  *
   1673  * @param cls closure
   1674  * @param result the postgres result
   1675  * @param num_results the number of results in @a result
   1676  */
   1677 static void
   1678 lrbt_cb_table_policy_fulfillments (void *cls,
   1679                                    PGresult *result,
   1680                                    unsigned int num_results)
   1681 {
   1682   struct LookupRecordsByTableContext *ctx = cls;
   1683   struct TALER_EXCHANGEDB_TableData td = {
   1684     .table = TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS
   1685   };
   1686 
   1687   for (unsigned int i = 0; i<num_results; i++)
   1688   {
   1689     bool no_proof = false;
   1690     bool no_timestamp = false;
   1691     struct GNUNET_PQ_ResultSpec rs[] = {
   1692       GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
   1693                                     &td.serial),
   1694       GNUNET_PQ_result_spec_allow_null (
   1695         GNUNET_PQ_result_spec_timestamp ("fulfillment_timestamp",
   1696                                          &td.details.policy_fulfillments.
   1697                                          fulfillment_timestamp),
   1698         &no_timestamp),
   1699       GNUNET_PQ_result_spec_allow_null (
   1700         GNUNET_PQ_result_spec_string ("fulfillment_proof",
   1701                                       &td.details.policy_fulfillments.
   1702                                       fulfillment_proof),
   1703         &no_proof),
   1704       GNUNET_PQ_result_spec_end
   1705     };
   1706 
   1707     if (GNUNET_OK !=
   1708         GNUNET_PQ_extract_result (result,
   1709                                   rs,
   1710                                   i))
   1711     {
   1712       GNUNET_break (0);
   1713       ctx->error = true;
   1714       return;
   1715     }
   1716     ctx->cb (ctx->cb_cls,
   1717              &td);
   1718     GNUNET_PQ_cleanup_result (rs);
   1719   }
   1720 }
   1721 
   1722 
   1723 /**
   1724  * Function called with purse_requests table entries.
   1725  *
   1726  * @param cls closure
   1727  * @param result the postgres result
   1728  * @param num_results the number of results in @a result
   1729  */
   1730 static void
   1731 lrbt_cb_table_purse_requests (void *cls,
   1732                               PGresult *result,
   1733                               unsigned int num_results)
   1734 {
   1735   struct LookupRecordsByTableContext *ctx = cls;
   1736   struct PostgresClosure *pg = ctx->pg;
   1737   struct TALER_EXCHANGEDB_TableData td = {
   1738     .table = TALER_EXCHANGEDB_RT_PURSE_REQUESTS
   1739   };
   1740 
   1741   for (unsigned int i = 0; i<num_results; i++)
   1742   {
   1743     struct GNUNET_PQ_ResultSpec rs[] = {
   1744       GNUNET_PQ_result_spec_uint64 (
   1745         "purse_requests_serial_id",
   1746         &td.serial),
   1747       GNUNET_PQ_result_spec_auto_from_type (
   1748         "purse_pub",
   1749         &td.details.purse_requests.purse_pub),
   1750       GNUNET_PQ_result_spec_auto_from_type (
   1751         "merge_pub",
   1752         &td.details.purse_requests.merge_pub),
   1753       GNUNET_PQ_result_spec_timestamp (
   1754         "purse_creation",
   1755         &td.details.purse_requests.purse_creation),
   1756       GNUNET_PQ_result_spec_timestamp (
   1757         "purse_expiration",
   1758         &td.details.purse_requests.purse_expiration),
   1759       GNUNET_PQ_result_spec_auto_from_type (
   1760         "h_contract_terms",
   1761         &td.details.purse_requests.h_contract_terms),
   1762       GNUNET_PQ_result_spec_uint32 (
   1763         "age_limit",
   1764         &td.details.purse_requests.age_limit),
   1765       GNUNET_PQ_result_spec_uint32 (
   1766         "flags",
   1767         &td.details.purse_requests.flags),
   1768       TALER_PQ_RESULT_SPEC_AMOUNT (
   1769         "amount_with_fee",
   1770         &td.details.purse_requests.amount_with_fee),
   1771       TALER_PQ_RESULT_SPEC_AMOUNT (
   1772         "purse_fee",
   1773         &td.details.purse_requests.purse_fee),
   1774       GNUNET_PQ_result_spec_auto_from_type (
   1775         "purse_sig",
   1776         &td.details.purse_requests.purse_sig),
   1777       GNUNET_PQ_result_spec_end
   1778     };
   1779 
   1780     if (GNUNET_OK !=
   1781         GNUNET_PQ_extract_result (result,
   1782                                   rs,
   1783                                   i))
   1784     {
   1785       GNUNET_break (0);
   1786       ctx->error = true;
   1787       return;
   1788     }
   1789     ctx->cb (ctx->cb_cls,
   1790              &td);
   1791     GNUNET_PQ_cleanup_result (rs);
   1792   }
   1793 }
   1794 
   1795 
   1796 /**
   1797  * Function called with purse_decision table entries.
   1798  *
   1799  * @param cls closure
   1800  * @param result the postgres result
   1801  * @param num_results the number of results in @a result
   1802  */
   1803 static void
   1804 lrbt_cb_table_purse_decision (void *cls,
   1805                               PGresult *result,
   1806                               unsigned int num_results)
   1807 {
   1808   struct LookupRecordsByTableContext *ctx = cls;
   1809   struct TALER_EXCHANGEDB_TableData td = {
   1810     .table = TALER_EXCHANGEDB_RT_PURSE_DECISION
   1811   };
   1812 
   1813   for (unsigned int i = 0; i<num_results; i++)
   1814   {
   1815     struct GNUNET_PQ_ResultSpec rs[] = {
   1816       GNUNET_PQ_result_spec_uint64 (
   1817         "purse_refunds_serial_id",
   1818         &td.serial),
   1819       GNUNET_PQ_result_spec_auto_from_type (
   1820         "purse_pub",
   1821         &td.details.purse_decision.purse_pub),
   1822       GNUNET_PQ_result_spec_timestamp (
   1823         "action_timestamp",
   1824         &td.details.purse_decision.action_timestamp),
   1825       GNUNET_PQ_result_spec_bool (
   1826         "refunded",
   1827         &td.details.purse_decision.refunded),
   1828       GNUNET_PQ_result_spec_end
   1829     };
   1830 
   1831     if (GNUNET_OK !=
   1832         GNUNET_PQ_extract_result (result,
   1833                                   rs,
   1834                                   i))
   1835     {
   1836       GNUNET_break (0);
   1837       ctx->error = true;
   1838       return;
   1839     }
   1840     ctx->cb (ctx->cb_cls,
   1841              &td);
   1842     GNUNET_PQ_cleanup_result (rs);
   1843   }
   1844 }
   1845 
   1846 
   1847 /**
   1848  * Function called with purse_merges table entries.
   1849  *
   1850  * @param cls closure
   1851  * @param result the postgres result
   1852  * @param num_results the number of results in @a result
   1853  */
   1854 static void
   1855 lrbt_cb_table_purse_merges (void *cls,
   1856                             PGresult *result,
   1857                             unsigned int num_results)
   1858 {
   1859   struct LookupRecordsByTableContext *ctx = cls;
   1860   struct TALER_EXCHANGEDB_TableData td = {
   1861     .table = TALER_EXCHANGEDB_RT_PURSE_MERGES
   1862   };
   1863 
   1864   for (unsigned int i = 0; i<num_results; i++)
   1865   {
   1866     struct GNUNET_PQ_ResultSpec rs[] = {
   1867       GNUNET_PQ_result_spec_uint64 (
   1868         "purse_merge_request_serial_id",
   1869         &td.serial),
   1870       GNUNET_PQ_result_spec_uint64 (
   1871         "partner_serial_id",
   1872         &td.details.purse_merges.partner_serial_id),
   1873       GNUNET_PQ_result_spec_auto_from_type (
   1874         "reserve_pub",
   1875         &td.details.purse_merges.reserve_pub),
   1876       GNUNET_PQ_result_spec_auto_from_type (
   1877         "purse_pub",
   1878         &td.details.purse_merges.purse_pub),
   1879       GNUNET_PQ_result_spec_auto_from_type (
   1880         "merge_sig",
   1881         &td.details.purse_merges.merge_sig),
   1882       GNUNET_PQ_result_spec_timestamp (
   1883         "merge_timestamp",
   1884         &td.details.purse_merges.merge_timestamp),
   1885       GNUNET_PQ_result_spec_end
   1886     };
   1887 
   1888     if (GNUNET_OK !=
   1889         GNUNET_PQ_extract_result (result,
   1890                                   rs,
   1891                                   i))
   1892     {
   1893       GNUNET_break (0);
   1894       ctx->error = true;
   1895       return;
   1896     }
   1897     ctx->cb (ctx->cb_cls,
   1898              &td);
   1899     GNUNET_PQ_cleanup_result (rs);
   1900   }
   1901 }
   1902 
   1903 
   1904 /**
   1905  * Function called with purse_deposits table entries.
   1906  *
   1907  * @param cls closure
   1908  * @param result the postgres result
   1909  * @param num_results the number of results in @a result
   1910  */
   1911 static void
   1912 lrbt_cb_table_purse_deposits (void *cls,
   1913                               PGresult *result,
   1914                               unsigned int num_results)
   1915 {
   1916   struct LookupRecordsByTableContext *ctx = cls;
   1917   struct PostgresClosure *pg = ctx->pg;
   1918   struct TALER_EXCHANGEDB_TableData td = {
   1919     .table = TALER_EXCHANGEDB_RT_PURSE_DEPOSITS
   1920   };
   1921 
   1922   for (unsigned int i = 0; i<num_results; i++)
   1923   {
   1924     struct GNUNET_PQ_ResultSpec rs[] = {
   1925       GNUNET_PQ_result_spec_uint64 (
   1926         "purse_deposit_serial_id",
   1927         &td.serial),
   1928       GNUNET_PQ_result_spec_uint64 (
   1929         "partner_serial_id",
   1930         &td.details.purse_deposits.partner_serial_id),
   1931       GNUNET_PQ_result_spec_auto_from_type (
   1932         "purse_pub",
   1933         &td.details.purse_deposits.purse_pub),
   1934       GNUNET_PQ_result_spec_auto_from_type (
   1935         "coin_pub",
   1936         &td.details.purse_deposits.coin_pub),
   1937       TALER_PQ_RESULT_SPEC_AMOUNT (
   1938         "amount_with_fee",
   1939         &td.details.purse_deposits.amount_with_fee),
   1940       GNUNET_PQ_result_spec_auto_from_type (
   1941         "coin_sig",
   1942         &td.details.purse_deposits.coin_sig),
   1943       GNUNET_PQ_result_spec_end
   1944     };
   1945 
   1946     if (GNUNET_OK !=
   1947         GNUNET_PQ_extract_result (result,
   1948                                   rs,
   1949                                   i))
   1950     {
   1951       GNUNET_break (0);
   1952       ctx->error = true;
   1953       return;
   1954     }
   1955     ctx->cb (ctx->cb_cls,
   1956              &td);
   1957     GNUNET_PQ_cleanup_result (rs);
   1958   }
   1959 }
   1960 
   1961 
   1962 /**
   1963  * Function called with account_merges table entries.
   1964  *
   1965  * @param cls closure
   1966  * @param result the postgres result
   1967  * @param num_results the number of results in @a result
   1968  */
   1969 static void
   1970 lrbt_cb_table_account_merges (void *cls,
   1971                               PGresult *result,
   1972                               unsigned int num_results)
   1973 {
   1974   struct LookupRecordsByTableContext *ctx = cls;
   1975   struct TALER_EXCHANGEDB_TableData td = {
   1976     .table = TALER_EXCHANGEDB_RT_ACCOUNT_MERGES
   1977   };
   1978 
   1979   for (unsigned int i = 0; i<num_results; i++)
   1980   {
   1981     struct GNUNET_PQ_ResultSpec rs[] = {
   1982       GNUNET_PQ_result_spec_uint64 (
   1983         "account_merge_request_serial_id",
   1984         &td.serial),
   1985       GNUNET_PQ_result_spec_auto_from_type (
   1986         "reserve_pub",
   1987         &td.details.account_merges.reserve_pub),
   1988       GNUNET_PQ_result_spec_auto_from_type (
   1989         "reserve_sig",
   1990         &td.details.account_merges.reserve_sig),
   1991       GNUNET_PQ_result_spec_auto_from_type (
   1992         "purse_pub",
   1993         &td.details.account_merges.purse_pub),
   1994       GNUNET_PQ_result_spec_auto_from_type (
   1995         "wallet_h_payto",
   1996         &td.details.account_merges.wallet_h_payto),
   1997       GNUNET_PQ_result_spec_end
   1998     };
   1999 
   2000     if (GNUNET_OK !=
   2001         GNUNET_PQ_extract_result (result,
   2002                                   rs,
   2003                                   i))
   2004     {
   2005       GNUNET_break (0);
   2006       ctx->error = true;
   2007       return;
   2008     }
   2009     ctx->cb (ctx->cb_cls,
   2010              &td);
   2011     GNUNET_PQ_cleanup_result (rs);
   2012   }
   2013 }
   2014 
   2015 
   2016 /**
   2017  * Function called with history_requests table entries.
   2018  *
   2019  * @param cls closure
   2020  * @param result the postgres result
   2021  * @param num_results the number of results in @a result
   2022  */
   2023 static void
   2024 lrbt_cb_table_history_requests (void *cls,
   2025                                 PGresult *result,
   2026                                 unsigned int num_results)
   2027 {
   2028   struct LookupRecordsByTableContext *ctx = cls;
   2029   struct PostgresClosure *pg = ctx->pg;
   2030   struct TALER_EXCHANGEDB_TableData td = {
   2031     .table = TALER_EXCHANGEDB_RT_HISTORY_REQUESTS
   2032   };
   2033 
   2034   for (unsigned int i = 0; i<num_results; i++)
   2035   {
   2036     struct GNUNET_PQ_ResultSpec rs[] = {
   2037       GNUNET_PQ_result_spec_uint64 (
   2038         "history_request_serial_id",
   2039         &td.serial),
   2040       GNUNET_PQ_result_spec_auto_from_type (
   2041         "reserve_pub",
   2042         &td.details.history_requests.reserve_pub),
   2043       GNUNET_PQ_result_spec_auto_from_type (
   2044         "reserve_sig",
   2045         &td.details.history_requests.reserve_sig),
   2046       TALER_PQ_RESULT_SPEC_AMOUNT (
   2047         "history_fee",
   2048         &td.details.history_requests.history_fee),
   2049       GNUNET_PQ_result_spec_end
   2050     };
   2051 
   2052     if (GNUNET_OK !=
   2053         GNUNET_PQ_extract_result (result,
   2054                                   rs,
   2055                                   i))
   2056     {
   2057       GNUNET_break (0);
   2058       ctx->error = true;
   2059       return;
   2060     }
   2061     ctx->cb (ctx->cb_cls,
   2062              &td);
   2063     GNUNET_PQ_cleanup_result (rs);
   2064   }
   2065 }
   2066 
   2067 
   2068 /**
   2069  * Function called with close_requests table entries.
   2070  *
   2071  * @param cls closure
   2072  * @param result the postgres result
   2073  * @param num_results the number of results in @a result
   2074  */
   2075 static void
   2076 lrbt_cb_table_close_requests (void *cls,
   2077                               PGresult *result,
   2078                               unsigned int num_results)
   2079 {
   2080   struct LookupRecordsByTableContext *ctx = cls;
   2081   struct PostgresClosure *pg = ctx->pg;
   2082   struct TALER_EXCHANGEDB_TableData td = {
   2083     .table = TALER_EXCHANGEDB_RT_CLOSE_REQUESTS
   2084   };
   2085 
   2086   for (unsigned int i = 0; i<num_results; i++)
   2087   {
   2088     struct GNUNET_PQ_ResultSpec rs[] = {
   2089       GNUNET_PQ_result_spec_uint64 (
   2090         "close_request_serial_id",
   2091         &td.serial),
   2092       GNUNET_PQ_result_spec_auto_from_type (
   2093         "reserve_pub",
   2094         &td.details.close_requests.reserve_pub),
   2095       GNUNET_PQ_result_spec_timestamp (
   2096         "close_timestamp",
   2097         &td.details.close_requests.close_timestamp),
   2098       GNUNET_PQ_result_spec_auto_from_type (
   2099         "reserve_sig",
   2100         &td.details.close_requests.reserve_sig),
   2101       TALER_PQ_RESULT_SPEC_AMOUNT (
   2102         "close",
   2103         &td.details.close_requests.close),
   2104       TALER_PQ_RESULT_SPEC_AMOUNT (
   2105         "close_fee",
   2106         &td.details.close_requests.close_fee),
   2107       GNUNET_PQ_result_spec_string (
   2108         "payto_uri",
   2109         &td.details.close_requests.payto_uri.full_payto),
   2110       GNUNET_PQ_result_spec_end
   2111     };
   2112 
   2113     if (GNUNET_OK !=
   2114         GNUNET_PQ_extract_result (result,
   2115                                   rs,
   2116                                   i))
   2117     {
   2118       GNUNET_break (0);
   2119       ctx->error = true;
   2120       return;
   2121     }
   2122     ctx->cb (ctx->cb_cls,
   2123              &td);
   2124     GNUNET_PQ_cleanup_result (rs);
   2125   }
   2126 }
   2127 
   2128 
   2129 /**
   2130  * Function called with wads_out table entries.
   2131  *
   2132  * @param cls closure
   2133  * @param result the postgres result
   2134  * @param num_results the number of results in @a result
   2135  */
   2136 static void
   2137 lrbt_cb_table_wads_out (void *cls,
   2138                         PGresult *result,
   2139                         unsigned int num_results)
   2140 {
   2141   struct LookupRecordsByTableContext *ctx = cls;
   2142   struct PostgresClosure *pg = ctx->pg;
   2143   struct TALER_EXCHANGEDB_TableData td = {
   2144     .table = TALER_EXCHANGEDB_RT_WADS_OUT
   2145   };
   2146 
   2147   for (unsigned int i = 0; i<num_results; i++)
   2148   {
   2149     struct GNUNET_PQ_ResultSpec rs[] = {
   2150       GNUNET_PQ_result_spec_uint64 (
   2151         "wad_out_serial_id",
   2152         &td.serial),
   2153       GNUNET_PQ_result_spec_auto_from_type (
   2154         "wad_id",
   2155         &td.details.wads_out.wad_id),
   2156       GNUNET_PQ_result_spec_uint64 (
   2157         "partner_serial_id",
   2158         &td.details.wads_out.partner_serial_id),
   2159       TALER_PQ_RESULT_SPEC_AMOUNT (
   2160         "amount",
   2161         &td.details.wads_out.amount),
   2162       GNUNET_PQ_result_spec_timestamp (
   2163         "execution_time",
   2164         &td.details.wads_out.execution_time),
   2165       GNUNET_PQ_result_spec_end
   2166     };
   2167 
   2168     if (GNUNET_OK !=
   2169         GNUNET_PQ_extract_result (result,
   2170                                   rs,
   2171                                   i))
   2172     {
   2173       GNUNET_break (0);
   2174       ctx->error = true;
   2175       return;
   2176     }
   2177     ctx->cb (ctx->cb_cls,
   2178              &td);
   2179     GNUNET_PQ_cleanup_result (rs);
   2180   }
   2181 }
   2182 
   2183 
   2184 /**
   2185  * Function called with wads_out_entries table entries.
   2186  *
   2187  * @param cls closure
   2188  * @param result the postgres result
   2189  * @param num_results the number of results in @a result
   2190  */
   2191 static void
   2192 lrbt_cb_table_wads_out_entries (void *cls,
   2193                                 PGresult *result,
   2194                                 unsigned int num_results)
   2195 {
   2196   struct LookupRecordsByTableContext *ctx = cls;
   2197   struct PostgresClosure *pg = ctx->pg;
   2198   struct TALER_EXCHANGEDB_TableData td = {
   2199     .table = TALER_EXCHANGEDB_RT_WADS_OUT_ENTRIES
   2200   };
   2201 
   2202   for (unsigned int i = 0; i<num_results; i++)
   2203   {
   2204     struct GNUNET_PQ_ResultSpec rs[] = {
   2205       GNUNET_PQ_result_spec_uint64 (
   2206         "wad_out_entry_serial_id",
   2207         &td.serial),
   2208       GNUNET_PQ_result_spec_auto_from_type (
   2209         "reserve_pub",
   2210         &td.details.wads_out_entries.reserve_pub),
   2211       GNUNET_PQ_result_spec_auto_from_type (
   2212         "purse_pub",
   2213         &td.details.wads_out_entries.purse_pub),
   2214       GNUNET_PQ_result_spec_auto_from_type (
   2215         "h_contract",
   2216         &td.details.wads_out_entries.h_contract),
   2217       GNUNET_PQ_result_spec_timestamp (
   2218         "purse_expiration",
   2219         &td.details.wads_out_entries.purse_expiration),
   2220       GNUNET_PQ_result_spec_timestamp (
   2221         "merge_timestamp",
   2222         &td.details.wads_out_entries.merge_timestamp),
   2223       TALER_PQ_RESULT_SPEC_AMOUNT (
   2224         "amount_with_fee",
   2225         &td.details.wads_out_entries.amount_with_fee),
   2226       TALER_PQ_RESULT_SPEC_AMOUNT (
   2227         "wad_fee",
   2228         &td.details.wads_out_entries.wad_fee),
   2229       TALER_PQ_RESULT_SPEC_AMOUNT (
   2230         "deposit_fees",
   2231         &td.details.wads_out_entries.deposit_fees),
   2232       GNUNET_PQ_result_spec_auto_from_type (
   2233         "reserve_sig",
   2234         &td.details.wads_out_entries.reserve_sig),
   2235       GNUNET_PQ_result_spec_auto_from_type (
   2236         "purse_sig",
   2237         &td.details.wads_out_entries.purse_sig),
   2238       GNUNET_PQ_result_spec_end
   2239     };
   2240 
   2241     if (GNUNET_OK !=
   2242         GNUNET_PQ_extract_result (result,
   2243                                   rs,
   2244                                   i))
   2245     {
   2246       GNUNET_break (0);
   2247       ctx->error = true;
   2248       return;
   2249     }
   2250     ctx->cb (ctx->cb_cls,
   2251              &td);
   2252     GNUNET_PQ_cleanup_result (rs);
   2253   }
   2254 }
   2255 
   2256 
   2257 /**
   2258  * Function called with wads_in table entries.
   2259  *
   2260  * @param cls closure
   2261  * @param result the postgres result
   2262  * @param num_results the number of results in @a result
   2263  */
   2264 static void
   2265 lrbt_cb_table_wads_in (void *cls,
   2266                        PGresult *result,
   2267                        unsigned int num_results)
   2268 {
   2269   struct LookupRecordsByTableContext *ctx = cls;
   2270   struct PostgresClosure *pg = ctx->pg;
   2271   struct TALER_EXCHANGEDB_TableData td = {
   2272     .table = TALER_EXCHANGEDB_RT_WADS_IN
   2273   };
   2274 
   2275   for (unsigned int i = 0; i<num_results; i++)
   2276   {
   2277     struct GNUNET_PQ_ResultSpec rs[] = {
   2278       GNUNET_PQ_result_spec_uint64 (
   2279         "wad_in_serial_id",
   2280         &td.serial),
   2281       GNUNET_PQ_result_spec_auto_from_type (
   2282         "wad_id",
   2283         &td.details.wads_in.wad_id),
   2284       GNUNET_PQ_result_spec_string (
   2285         "origin_exchange_url",
   2286         &td.details.wads_in.origin_exchange_url),
   2287       TALER_PQ_RESULT_SPEC_AMOUNT (
   2288         "amount",
   2289         &td.details.wads_in.amount),
   2290       GNUNET_PQ_result_spec_timestamp (
   2291         "arrival_time",
   2292         &td.details.wads_in.arrival_time),
   2293       GNUNET_PQ_result_spec_end
   2294     };
   2295 
   2296     if (GNUNET_OK !=
   2297         GNUNET_PQ_extract_result (result,
   2298                                   rs,
   2299                                   i))
   2300     {
   2301       GNUNET_break (0);
   2302       ctx->error = true;
   2303       return;
   2304     }
   2305     ctx->cb (ctx->cb_cls,
   2306              &td);
   2307     GNUNET_PQ_cleanup_result (rs);
   2308   }
   2309 }
   2310 
   2311 
   2312 /**
   2313  * Function called with wads_in_entries table entries.
   2314  *
   2315  * @param cls closure
   2316  * @param result the postgres result
   2317  * @param num_results the number of results in @a result
   2318  */
   2319 static void
   2320 lrbt_cb_table_wads_in_entries (void *cls,
   2321                                PGresult *result,
   2322                                unsigned int num_results)
   2323 {
   2324   struct LookupRecordsByTableContext *ctx = cls;
   2325   struct PostgresClosure *pg = ctx->pg;
   2326   struct TALER_EXCHANGEDB_TableData td = {
   2327     .table = TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES
   2328   };
   2329 
   2330   for (unsigned int i = 0; i<num_results; i++)
   2331   {
   2332     struct GNUNET_PQ_ResultSpec rs[] = {
   2333       GNUNET_PQ_result_spec_uint64 (
   2334         "wad_in_entry_serial_id",
   2335         &td.serial),
   2336       GNUNET_PQ_result_spec_auto_from_type (
   2337         "reserve_pub",
   2338         &td.details.wads_in_entries.reserve_pub),
   2339       GNUNET_PQ_result_spec_auto_from_type (
   2340         "purse_pub",
   2341         &td.details.wads_in_entries.purse_pub),
   2342       GNUNET_PQ_result_spec_auto_from_type (
   2343         "h_contract",
   2344         &td.details.wads_in_entries.h_contract),
   2345       GNUNET_PQ_result_spec_timestamp (
   2346         "purse_expiration",
   2347         &td.details.wads_in_entries.purse_expiration),
   2348       GNUNET_PQ_result_spec_timestamp (
   2349         "merge_timestamp",
   2350         &td.details.wads_in_entries.merge_timestamp),
   2351       TALER_PQ_RESULT_SPEC_AMOUNT (
   2352         "amount_with_fee",
   2353         &td.details.wads_in_entries.amount_with_fee),
   2354       TALER_PQ_RESULT_SPEC_AMOUNT (
   2355         "wad_fee",
   2356         &td.details.wads_in_entries.wad_fee),
   2357       TALER_PQ_RESULT_SPEC_AMOUNT (
   2358         "deposit_fees",
   2359         &td.details.wads_in_entries.deposit_fees),
   2360       GNUNET_PQ_result_spec_auto_from_type (
   2361         "reserve_sig",
   2362         &td.details.wads_in_entries.reserve_sig),
   2363       GNUNET_PQ_result_spec_auto_from_type (
   2364         "purse_sig",
   2365         &td.details.wads_in_entries.purse_sig),
   2366       GNUNET_PQ_result_spec_end
   2367     };
   2368 
   2369     if (GNUNET_OK !=
   2370         GNUNET_PQ_extract_result (result,
   2371                                   rs,
   2372                                   i))
   2373     {
   2374       GNUNET_break (0);
   2375       ctx->error = true;
   2376       return;
   2377     }
   2378     ctx->cb (ctx->cb_cls,
   2379              &td);
   2380     GNUNET_PQ_cleanup_result (rs);
   2381   }
   2382 }
   2383 
   2384 
   2385 /**
   2386  * Function called with profit_drains table entries.
   2387  *
   2388  * @param cls closure
   2389  * @param result the postgres result
   2390  * @param num_results the number of results in @a result
   2391  */
   2392 static void
   2393 lrbt_cb_table_profit_drains (void *cls,
   2394                              PGresult *result,
   2395                              unsigned int num_results)
   2396 {
   2397   struct LookupRecordsByTableContext *ctx = cls;
   2398   struct PostgresClosure *pg = ctx->pg;
   2399   struct TALER_EXCHANGEDB_TableData td = {
   2400     .table = TALER_EXCHANGEDB_RT_PROFIT_DRAINS
   2401   };
   2402 
   2403   for (unsigned int i = 0; i<num_results; i++)
   2404   {
   2405     struct GNUNET_PQ_ResultSpec rs[] = {
   2406       GNUNET_PQ_result_spec_uint64 (
   2407         "profit_drain_serial_id",
   2408         &td.serial),
   2409       GNUNET_PQ_result_spec_auto_from_type (
   2410         "wtid",
   2411         &td.details.profit_drains.wtid),
   2412       GNUNET_PQ_result_spec_string (
   2413         "account_section",
   2414         &td.details.profit_drains.account_section),
   2415       GNUNET_PQ_result_spec_string (
   2416         "payto_uri",
   2417         &td.details.profit_drains.payto_uri.full_payto),
   2418       GNUNET_PQ_result_spec_timestamp (
   2419         "trigger_date",
   2420         &td.details.profit_drains.trigger_date),
   2421       TALER_PQ_RESULT_SPEC_AMOUNT (
   2422         "amount",
   2423         &td.details.profit_drains.amount),
   2424       GNUNET_PQ_result_spec_auto_from_type (
   2425         "master_sig",
   2426         &td.details.profit_drains.master_sig),
   2427       GNUNET_PQ_result_spec_end
   2428     };
   2429 
   2430     if (GNUNET_OK !=
   2431         GNUNET_PQ_extract_result (result,
   2432                                   rs,
   2433                                   i))
   2434     {
   2435       GNUNET_break (0);
   2436       ctx->error = true;
   2437       return;
   2438     }
   2439     ctx->cb (ctx->cb_cls,
   2440              &td);
   2441     GNUNET_PQ_cleanup_result (rs);
   2442   }
   2443 }
   2444 
   2445 
   2446 /**
   2447  * Function called with aml_staff table entries.
   2448  *
   2449  * @param cls closure
   2450  * @param result the postgres result
   2451  * @param num_results the number of results in @a result
   2452  */
   2453 static void
   2454 lrbt_cb_table_aml_staff (void *cls,
   2455                          PGresult *result,
   2456                          unsigned int num_results)
   2457 {
   2458   struct LookupRecordsByTableContext *ctx = cls;
   2459   struct TALER_EXCHANGEDB_TableData td = {
   2460     .table = TALER_EXCHANGEDB_RT_AML_STAFF
   2461   };
   2462 
   2463   for (unsigned int i = 0; i<num_results; i++)
   2464   {
   2465     struct GNUNET_PQ_ResultSpec rs[] = {
   2466       GNUNET_PQ_result_spec_uint64 (
   2467         "aml_staff_uuid",
   2468         &td.serial),
   2469       GNUNET_PQ_result_spec_auto_from_type (
   2470         "decider_pub",
   2471         &td.details.aml_staff.decider_pub),
   2472       GNUNET_PQ_result_spec_auto_from_type (
   2473         "master_sig",
   2474         &td.details.aml_staff.master_sig),
   2475       GNUNET_PQ_result_spec_string (
   2476         "decider_name",
   2477         &td.details.aml_staff.decider_name),
   2478       GNUNET_PQ_result_spec_bool (
   2479         "is_active",
   2480         &td.details.aml_staff.is_active),
   2481       GNUNET_PQ_result_spec_bool (
   2482         "read_only",
   2483         &td.details.aml_staff.read_only),
   2484       GNUNET_PQ_result_spec_timestamp (
   2485         "last_change",
   2486         &td.details.aml_staff.last_change),
   2487       GNUNET_PQ_result_spec_end
   2488     };
   2489 
   2490     if (GNUNET_OK !=
   2491         GNUNET_PQ_extract_result (result,
   2492                                   rs,
   2493                                   i))
   2494     {
   2495       GNUNET_break (0);
   2496       ctx->error = true;
   2497       return;
   2498     }
   2499     ctx->cb (ctx->cb_cls,
   2500              &td);
   2501     GNUNET_PQ_cleanup_result (rs);
   2502   }
   2503 }
   2504 
   2505 
   2506 /**
   2507  * Function called with purse_deletion table entries.
   2508  *
   2509  * @param cls closure
   2510  * @param result the postgres result
   2511  * @param num_results the number of results in @a result
   2512  */
   2513 static void
   2514 lrbt_cb_table_purse_deletion (void *cls,
   2515                               PGresult *result,
   2516                               unsigned int num_results)
   2517 {
   2518   struct LookupRecordsByTableContext *ctx = cls;
   2519   struct TALER_EXCHANGEDB_TableData td = {
   2520     .table = TALER_EXCHANGEDB_RT_PURSE_DELETION
   2521   };
   2522 
   2523   for (unsigned int i = 0; i<num_results; i++)
   2524   {
   2525     struct GNUNET_PQ_ResultSpec rs[] = {
   2526       GNUNET_PQ_result_spec_uint64 (
   2527         "purse_deletion_serial_id",
   2528         &td.serial),
   2529       GNUNET_PQ_result_spec_auto_from_type (
   2530         "purse_sig",
   2531         &td.details.purse_deletion.purse_sig),
   2532       GNUNET_PQ_result_spec_auto_from_type (
   2533         "purse_pub",
   2534         &td.details.purse_deletion.purse_pub),
   2535       GNUNET_PQ_result_spec_end
   2536     };
   2537 
   2538     if (GNUNET_OK !=
   2539         GNUNET_PQ_extract_result (result,
   2540                                   rs,
   2541                                   i))
   2542     {
   2543       GNUNET_break (0);
   2544       ctx->error = true;
   2545       return;
   2546     }
   2547     ctx->cb (ctx->cb_cls,
   2548              &td);
   2549     GNUNET_PQ_cleanup_result (rs);
   2550   }
   2551 }
   2552 
   2553 
   2554 /**
   2555  * Function called with withdraw table entries.
   2556  *
   2557  * @param cls closure
   2558  * @param result the postgres result
   2559  * @param num_results the number of results in @a result
   2560  */
   2561 static void
   2562 lrbt_cb_table_withdraw (void *cls,
   2563                         PGresult *result,
   2564                         unsigned int num_results)
   2565 {
   2566   struct LookupRecordsByTableContext *ctx = cls;
   2567   struct PostgresClosure *pg = ctx->pg;
   2568   struct TALER_EXCHANGEDB_TableData td = {
   2569     .table = TALER_EXCHANGEDB_RT_WITHDRAW
   2570   };
   2571 
   2572   for (unsigned int i = 0; i<num_results; i++)
   2573   {
   2574     bool no_max_age;
   2575     bool no_noreveal_index;
   2576     bool no_selected_h;
   2577     bool no_cs_r_values;
   2578     bool no_cs_r_choices;
   2579     size_t num_sigs;
   2580     struct GNUNET_PQ_ResultSpec rs[] = {
   2581       GNUNET_PQ_result_spec_uint64 (
   2582         "withdraw_id",
   2583         &td.serial),
   2584       GNUNET_PQ_result_spec_auto_from_type (
   2585         "planchets_h",
   2586         &td.details.withdraw.planchets_h),
   2587       GNUNET_PQ_result_spec_timestamp (
   2588         "execution_date",
   2589         &td.details.withdraw.execution_date),
   2590       TALER_PQ_RESULT_SPEC_AMOUNT (
   2591         "amount_with_fee",
   2592         &td.details.withdraw.amount_with_fee),
   2593       GNUNET_PQ_result_spec_auto_from_type (
   2594         "reserve_pub",
   2595         &td.details.withdraw.reserve_pub),
   2596       GNUNET_PQ_result_spec_auto_from_type (
   2597         "reserve_sig",
   2598         &td.details.withdraw.reserve_sig),
   2599       GNUNET_PQ_result_spec_allow_null (
   2600         GNUNET_PQ_result_spec_uint16 (
   2601           "max_age",
   2602           &td.details.withdraw.max_age),
   2603         &no_max_age),
   2604       GNUNET_PQ_result_spec_allow_null (
   2605         GNUNET_PQ_result_spec_uint16 (
   2606           "noreveal_index",
   2607           &td.details.withdraw.noreveal_index),
   2608         &no_noreveal_index),
   2609       GNUNET_PQ_result_spec_allow_null (
   2610         GNUNET_PQ_result_spec_auto_from_type (
   2611           "selected_h",
   2612           &td.details.withdraw.selected_h),
   2613         &no_selected_h),
   2614       GNUNET_PQ_result_spec_allow_null (
   2615         GNUNET_PQ_result_spec_auto_from_type (
   2616           "blinding_seed",
   2617           &td.details.withdraw.blinding_seed),
   2618         &td.details.withdraw.no_blinding_seed),
   2619       GNUNET_PQ_result_spec_allow_null (
   2620         TALER_PQ_result_spec_array_cs_r_pub (
   2621           pg->conn,
   2622           "cs_r_values",
   2623           &td.details.withdraw.num_cs_r_values,
   2624           &td.details.withdraw.cs_r_values),
   2625         &no_cs_r_values),
   2626       GNUNET_PQ_result_spec_allow_null (
   2627         GNUNET_PQ_result_spec_uint64 (
   2628           "cs_r_choices",
   2629           &td.details.withdraw.cs_r_choices),
   2630         &no_cs_r_choices),
   2631       GNUNET_PQ_result_spec_array_uint64 (
   2632         pg->conn,
   2633         "denom_serials",
   2634         &td.details.withdraw.num_coins,
   2635         &td.details.withdraw.denom_serials),
   2636       TALER_PQ_result_spec_array_blinded_denom_sig (
   2637         pg->conn,
   2638         "denom_sigs",
   2639         &num_sigs,
   2640         &td.details.withdraw.denom_sigs),
   2641       GNUNET_PQ_result_spec_end
   2642     };
   2643 
   2644     if (GNUNET_OK !=
   2645         GNUNET_PQ_extract_result (result,
   2646                                   rs,
   2647                                   i))
   2648     {
   2649       GNUNET_break (0);
   2650       ctx->error = true;
   2651       GNUNET_PQ_cleanup_result (rs);
   2652       return;
   2653     }
   2654     if (num_sigs != td.details.withdraw.num_coins)
   2655     {
   2656       GNUNET_break (0);
   2657       ctx->error = true;
   2658       GNUNET_PQ_cleanup_result (rs);
   2659       return;
   2660     }
   2661     if (no_max_age != no_noreveal_index)
   2662     {
   2663       GNUNET_break (0);
   2664       ctx->error = true;
   2665       GNUNET_PQ_cleanup_result (rs);
   2666       return;
   2667     }
   2668     if (no_max_age != no_selected_h)
   2669     {
   2670       GNUNET_break (0);
   2671       ctx->error = true;
   2672       GNUNET_PQ_cleanup_result (rs);
   2673       return;
   2674     }
   2675     if (no_cs_r_values != no_cs_r_choices)
   2676     {
   2677       GNUNET_break (0);
   2678       ctx->error = true;
   2679       GNUNET_PQ_cleanup_result (rs);
   2680       return;
   2681     }
   2682     if (no_cs_r_values != td.details.withdraw.no_blinding_seed)
   2683     {
   2684       GNUNET_break (0);
   2685       ctx->error = true;
   2686       GNUNET_PQ_cleanup_result (rs);
   2687       return;
   2688     }
   2689     td.details.withdraw.age_proof_required = ! no_max_age;
   2690     ctx->cb (ctx->cb_cls,
   2691              &td);
   2692     GNUNET_PQ_cleanup_result (rs);
   2693   }
   2694 }
   2695 
   2696 
   2697 /**
   2698  * Function called with legitimization_measures table entries.
   2699  *
   2700  * @param cls closure
   2701  * @param result the postgres result
   2702  * @param num_results the number of results in @a result
   2703  */
   2704 static void
   2705 lrbt_cb_table_legitimization_measures (void *cls,
   2706                                        PGresult *result,
   2707                                        unsigned int num_results)
   2708 {
   2709   struct LookupRecordsByTableContext *ctx = cls;
   2710   struct TALER_EXCHANGEDB_TableData td = {
   2711     .table = TALER_EXCHANGEDB_RT_LEGITIMIZATION_MEASURES
   2712   };
   2713 
   2714   for (unsigned int i = 0; i<num_results; i++)
   2715   {
   2716     struct GNUNET_PQ_ResultSpec rs[] = {
   2717       GNUNET_PQ_result_spec_uint64 ("serial",
   2718                                     &td.serial),
   2719       GNUNET_PQ_result_spec_auto_from_type (
   2720         "access_token",
   2721         &td.details.legitimization_measures.target_token),
   2722       GNUNET_PQ_result_spec_timestamp (
   2723         "start_time",
   2724         &td.details.legitimization_measures.start_time),
   2725       TALER_PQ_result_spec_json (
   2726         "jmeasures",
   2727         &td.details.legitimization_measures.measures),
   2728       GNUNET_PQ_result_spec_uint32 (
   2729         "display_priority",
   2730         &td.details.legitimization_measures.display_priority),
   2731       GNUNET_PQ_result_spec_end
   2732     };
   2733 
   2734     if (GNUNET_OK !=
   2735         GNUNET_PQ_extract_result (result,
   2736                                   rs,
   2737                                   i))
   2738     {
   2739       GNUNET_break (0);
   2740       ctx->error = true;
   2741       return;
   2742     }
   2743     ctx->cb (ctx->cb_cls,
   2744              &td);
   2745     GNUNET_PQ_cleanup_result (rs);
   2746   }
   2747 }
   2748 
   2749 
   2750 /**
   2751  * Function called with legitimization_outcomes table entries.
   2752  *
   2753  * @param cls closure
   2754  * @param result the postgres result
   2755  * @param num_results the number of results in @a result
   2756  */
   2757 static void
   2758 lrbt_cb_table_legitimization_outcomes (void *cls,
   2759                                        PGresult *result,
   2760                                        unsigned int num_results)
   2761 {
   2762   struct LookupRecordsByTableContext *ctx = cls;
   2763   struct TALER_EXCHANGEDB_TableData td = {
   2764     .table = TALER_EXCHANGEDB_RT_LEGITIMIZATION_OUTCOMES
   2765   };
   2766 
   2767   for (unsigned int i = 0; i<num_results; i++)
   2768   {
   2769     struct GNUNET_PQ_ResultSpec rs[] = {
   2770       GNUNET_PQ_result_spec_uint64 ("serial",
   2771                                     &td.serial),
   2772       GNUNET_PQ_result_spec_auto_from_type (
   2773         "h_payto",
   2774         &td.details.legitimization_outcomes.h_payto),
   2775       GNUNET_PQ_result_spec_timestamp (
   2776         "decision_time",
   2777         &td.details.legitimization_outcomes.decision_time),
   2778       GNUNET_PQ_result_spec_timestamp (
   2779         "expiration_time",
   2780         &td.details.legitimization_outcomes.expiration_time),
   2781       GNUNET_PQ_result_spec_allow_null (
   2782         TALER_PQ_result_spec_json (
   2783           "jproperties",
   2784           &td.details.legitimization_outcomes.properties),
   2785         NULL),
   2786       GNUNET_PQ_result_spec_bool (
   2787         "to_investigate_id",
   2788         &td.details.legitimization_outcomes.to_investigate),
   2789       TALER_PQ_result_spec_json (
   2790         "jnew_rules",
   2791         &td.details.legitimization_outcomes.new_rules),
   2792       GNUNET_PQ_result_spec_end
   2793     };
   2794 
   2795     if (GNUNET_OK !=
   2796         GNUNET_PQ_extract_result (result,
   2797                                   rs,
   2798                                   i))
   2799     {
   2800       GNUNET_break (0);
   2801       ctx->error = true;
   2802       return;
   2803     }
   2804     ctx->cb (ctx->cb_cls,
   2805              &td);
   2806     GNUNET_PQ_cleanup_result (rs);
   2807   }
   2808 }
   2809 
   2810 
   2811 /**
   2812  * Function called with legitimization_processes table entries.
   2813  *
   2814  * @param cls closure
   2815  * @param result the postgres result
   2816  * @param num_results the number of results in @a result
   2817  */
   2818 static void
   2819 lrbt_cb_table_legitimization_processes (void *cls,
   2820                                         PGresult *result,
   2821                                         unsigned int num_results)
   2822 {
   2823   struct LookupRecordsByTableContext *ctx = cls;
   2824   struct TALER_EXCHANGEDB_TableData td = {
   2825     .table = TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES
   2826   };
   2827 
   2828   for (unsigned int i = 0; i<num_results; i++)
   2829   {
   2830     struct GNUNET_PQ_ResultSpec rs[] = {
   2831       GNUNET_PQ_result_spec_uint64 ("serial",
   2832                                     &td.serial),
   2833       GNUNET_PQ_result_spec_auto_from_type (
   2834         "h_payto",
   2835         &td.details.legitimization_processes.h_payto),
   2836       GNUNET_PQ_result_spec_timestamp (
   2837         "start_time",
   2838         &td.details.legitimization_processes.start_time),
   2839       GNUNET_PQ_result_spec_timestamp (
   2840         "expiration_time",
   2841         &td.details.legitimization_processes.expiration_time),
   2842       GNUNET_PQ_result_spec_uint64 (
   2843         "legitimization_measure_serial_id",
   2844         &td.details.legitimization_processes.legitimization_measure_serial_id),
   2845       GNUNET_PQ_result_spec_uint32 (
   2846         "measure_index",
   2847         &td.details.legitimization_processes.measure_index),
   2848       GNUNET_PQ_result_spec_string (
   2849         "provider_name",
   2850         &td.details.legitimization_processes.provider_name),
   2851       GNUNET_PQ_result_spec_string (
   2852         "provider_user_id",
   2853         &td.details.legitimization_processes.provider_user_id),
   2854       GNUNET_PQ_result_spec_string (
   2855         "provider_legitimization_id",
   2856         &td.details.legitimization_processes.provider_legitimization_id),
   2857       GNUNET_PQ_result_spec_string (
   2858         "redirect_url",
   2859         &td.details.legitimization_processes.redirect_url),
   2860       GNUNET_PQ_result_spec_end
   2861     };
   2862 
   2863     if (GNUNET_OK !=
   2864         GNUNET_PQ_extract_result (result,
   2865                                   rs,
   2866                                   i))
   2867     {
   2868       GNUNET_break (0);
   2869       ctx->error = true;
   2870       return;
   2871     }
   2872     ctx->cb (ctx->cb_cls,
   2873              &td);
   2874     GNUNET_PQ_cleanup_result (rs);
   2875   }
   2876 }
   2877 
   2878 
   2879 /**
   2880  * Function called with kyc_attributes table entries.
   2881  *
   2882  * @param cls closure
   2883  * @param result the postgres result
   2884  * @param num_results the number of results in @a result
   2885  */
   2886 static void
   2887 lrbt_cb_table_kyc_attributes (void *cls,
   2888                               PGresult *result,
   2889                               unsigned int num_results)
   2890 {
   2891   struct LookupRecordsByTableContext *ctx = cls;
   2892   struct TALER_EXCHANGEDB_TableData td = {
   2893     .table = TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES
   2894   };
   2895 
   2896   for (unsigned int i = 0; i<num_results; i++)
   2897   {
   2898     struct GNUNET_PQ_ResultSpec rs[] = {
   2899       GNUNET_PQ_result_spec_uint64 (
   2900         "kyc_attributes_serial_id",
   2901         &td.serial),
   2902       GNUNET_PQ_result_spec_auto_from_type (
   2903         "h_payto",
   2904         &td.details.kyc_attributes.h_payto),
   2905       GNUNET_PQ_result_spec_uint64 (
   2906         "legitimization_serial",
   2907         &td.details.kyc_attributes.legitimization_serial),
   2908       GNUNET_PQ_result_spec_timestamp (
   2909         "collection_time",
   2910         &td.details.kyc_attributes.collection_time),
   2911       GNUNET_PQ_result_spec_timestamp (
   2912         "expiration_time",
   2913         &td.details.kyc_attributes.expiration_time),
   2914       GNUNET_PQ_result_spec_uint64 (
   2915         "trigger_outcome_serial",
   2916         &td.details.kyc_attributes.trigger_outcome_serial),
   2917       GNUNET_PQ_result_spec_variable_size (
   2918         "encrypted_attributes",
   2919         &td.details.kyc_attributes.encrypted_attributes,
   2920         &td.details.kyc_attributes.encrypted_attributes_size),
   2921       GNUNET_PQ_result_spec_end
   2922     };
   2923 
   2924     if (GNUNET_OK !=
   2925         GNUNET_PQ_extract_result (result,
   2926                                   rs,
   2927                                   i))
   2928     {
   2929       GNUNET_break (0);
   2930       ctx->error = true;
   2931       return;
   2932     }
   2933     ctx->cb (ctx->cb_cls,
   2934              &td);
   2935     GNUNET_PQ_cleanup_result (rs);
   2936   }
   2937 }
   2938 
   2939 
   2940 /**
   2941  * Function called with aml_history table entries.
   2942  *
   2943  * @param cls closure
   2944  * @param result the postgres result
   2945  * @param num_results the number of results in @a result
   2946  */
   2947 static void
   2948 lrbt_cb_table_aml_history (void *cls,
   2949                            PGresult *result,
   2950                            unsigned int num_results)
   2951 {
   2952   struct LookupRecordsByTableContext *ctx = cls;
   2953   struct TALER_EXCHANGEDB_TableData td = {
   2954     .table = TALER_EXCHANGEDB_RT_AML_HISTORY
   2955   };
   2956 
   2957   for (unsigned int i = 0; i<num_results; i++)
   2958   {
   2959     struct GNUNET_PQ_ResultSpec rs[] = {
   2960       GNUNET_PQ_result_spec_uint64 (
   2961         "aml_history_serial_id",
   2962         &td.serial),
   2963       GNUNET_PQ_result_spec_auto_from_type (
   2964         "h_payto",
   2965         &td.details.aml_history.h_payto),
   2966       GNUNET_PQ_result_spec_uint64 (
   2967         "outcome_serial_id",
   2968         &td.details.aml_history.outcome_serial_id),
   2969       GNUNET_PQ_result_spec_string (
   2970         "justification",
   2971         &td.details.aml_history.justification),
   2972       GNUNET_PQ_result_spec_auto_from_type (
   2973         "decider_pub",
   2974         &td.details.aml_history.decider_pub),
   2975       GNUNET_PQ_result_spec_auto_from_type (
   2976         "decider_sig",
   2977         &td.details.aml_history.decider_sig),
   2978       GNUNET_PQ_result_spec_end
   2979     };
   2980 
   2981     if (GNUNET_OK !=
   2982         GNUNET_PQ_extract_result (result,
   2983                                   rs,
   2984                                   i))
   2985     {
   2986       GNUNET_break (0);
   2987       ctx->error = true;
   2988       return;
   2989     }
   2990     ctx->cb (ctx->cb_cls,
   2991              &td);
   2992     GNUNET_PQ_cleanup_result (rs);
   2993   }
   2994 }
   2995 
   2996 
   2997 /**
   2998  * Function called with kyc_events table entries.
   2999  *
   3000  * @param cls closure
   3001  * @param result the postgres result
   3002  * @param num_results the number of results in @a result
   3003  */
   3004 static void
   3005 lrbt_cb_table_kyc_events (void *cls,
   3006                           PGresult *result,
   3007                           unsigned int num_results)
   3008 {
   3009   struct LookupRecordsByTableContext *ctx = cls;
   3010   struct TALER_EXCHANGEDB_TableData td = {
   3011     .table = TALER_EXCHANGEDB_RT_KYC_EVENTS
   3012   };
   3013 
   3014   for (unsigned int i = 0; i<num_results; i++)
   3015   {
   3016     struct GNUNET_PQ_ResultSpec rs[] = {
   3017       GNUNET_PQ_result_spec_uint64 (
   3018         "kyc_event_serial_id",
   3019         &td.serial),
   3020       GNUNET_PQ_result_spec_timestamp (
   3021         "event_timestamp",
   3022         &td.details.kyc_events.event_timestamp),
   3023       GNUNET_PQ_result_spec_string (
   3024         "event_type",
   3025         &td.details.kyc_events.event_type),
   3026       GNUNET_PQ_result_spec_end
   3027     };
   3028 
   3029     if (GNUNET_OK !=
   3030         GNUNET_PQ_extract_result (result,
   3031                                   rs,
   3032                                   i))
   3033     {
   3034       GNUNET_break (0);
   3035       ctx->error = true;
   3036       return;
   3037     }
   3038     ctx->cb (ctx->cb_cls,
   3039              &td);
   3040     GNUNET_PQ_cleanup_result (rs);
   3041   }
   3042 }
   3043 
   3044 
   3045 /**
   3046  * Assign statement to @a n and PREPARE
   3047  * @a sql under name @a n.
   3048  */
   3049 #define XPREPARE(n,sql) \
   3050         statement = n;        \
   3051         PREPARE (pg, n, sql);
   3052 
   3053 
   3054 enum GNUNET_DB_QueryStatus
   3055 TEH_PG_lookup_records_by_table (void *cls,
   3056                                 enum TALER_EXCHANGEDB_ReplicatedTable table,
   3057                                 uint64_t serial,
   3058                                 TALER_EXCHANGEDB_ReplicationCallback cb,
   3059                                 void *cb_cls)
   3060 {
   3061   struct PostgresClosure *pg = cls;
   3062   struct GNUNET_PQ_QueryParam params[] = {
   3063     GNUNET_PQ_query_param_uint64 (&serial),
   3064     GNUNET_PQ_query_param_end
   3065   };
   3066   struct LookupRecordsByTableContext ctx = {
   3067     .pg = pg,
   3068     .cb = cb,
   3069     .cb_cls = cb_cls
   3070   };
   3071   GNUNET_PQ_PostgresResultHandler rh = NULL;
   3072   const char *statement = NULL;
   3073   enum GNUNET_DB_QueryStatus qs;
   3074 
   3075   switch (table)
   3076   {
   3077   case TALER_EXCHANGEDB_RT_DENOMINATIONS:
   3078     XPREPARE ("select_above_serial_by_table_denominations",
   3079               "SELECT"
   3080               " denominations_serial AS serial"
   3081               ",denom_type"
   3082               ",denom_pub"
   3083               ",master_sig"
   3084               ",valid_from"
   3085               ",expire_withdraw"
   3086               ",expire_deposit"
   3087               ",expire_legal"
   3088               ",coin"
   3089               ",fee_withdraw"
   3090               ",fee_deposit"
   3091               ",fee_refresh"
   3092               ",fee_refund"
   3093               ",age_mask"
   3094               " FROM denominations"
   3095               " WHERE denominations_serial > $1"
   3096               " ORDER BY denominations_serial ASC;");
   3097     rh = &lrbt_cb_table_denominations;
   3098     break;
   3099   case TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS:
   3100     XPREPARE ("select_above_serial_by_table_denomination_revocations",
   3101               "SELECT"
   3102               " denom_revocations_serial_id AS serial"
   3103               ",master_sig"
   3104               ",denominations_serial"
   3105               " FROM denomination_revocations"
   3106               " WHERE denom_revocations_serial_id > $1"
   3107               " ORDER BY denom_revocations_serial_id ASC;");
   3108     rh = &lrbt_cb_table_denomination_revocations;
   3109     break;
   3110   case TALER_EXCHANGEDB_RT_WIRE_TARGETS:
   3111     XPREPARE ("select_above_serial_by_table_wire_targets",
   3112               "SELECT"
   3113               " wire_target_serial_id AS serial"
   3114               ",payto_uri"
   3115               " FROM wire_targets"
   3116               " WHERE wire_target_serial_id > $1"
   3117               " ORDER BY wire_target_serial_id ASC;");
   3118     rh = &lrbt_cb_table_wire_targets;
   3119     break;
   3120   case TALER_EXCHANGEDB_RT_KYC_TARGETS:
   3121     XPREPARE ("select_above_serial_by_table_kyc_targets",
   3122               "SELECT"
   3123               " kyc_target_serial_id AS serial"
   3124               ",h_normalized_payto"
   3125               ",access_token"
   3126               ",target_pub"
   3127               ",is_wallet"
   3128               " FROM kyc_targets"
   3129               " WHERE kyc_target_serial_id > $1"
   3130               " ORDER BY kyc_target_serial_id ASC;");
   3131     rh = &lrbt_cb_table_kyc_targets;
   3132     break;
   3133   case TALER_EXCHANGEDB_RT_RESERVES:
   3134     XPREPARE ("select_above_serial_by_table_reserves",
   3135               "SELECT"
   3136               " reserve_uuid AS serial"
   3137               ",reserve_pub"
   3138               ",expiration_date"
   3139               ",gc_date"
   3140               " FROM reserves"
   3141               " WHERE reserve_uuid > $1"
   3142               " ORDER BY reserve_uuid ASC;");
   3143     rh = &lrbt_cb_table_reserves;
   3144     break;
   3145   case TALER_EXCHANGEDB_RT_RESERVES_IN:
   3146     XPREPARE ("select_above_serial_by_table_reserves_in",
   3147               "SELECT"
   3148               " reserve_in_serial_id AS serial"
   3149               ",reserve_pub"
   3150               ",wire_reference"
   3151               ",credit"
   3152               ",wire_source_h_payto"
   3153               ",exchange_account_section"
   3154               ",execution_date"
   3155               " FROM reserves_in"
   3156               " WHERE reserve_in_serial_id > $1"
   3157               " ORDER BY reserve_in_serial_id ASC;");
   3158     rh = &lrbt_cb_table_reserves_in;
   3159     break;
   3160   case TALER_EXCHANGEDB_RT_KYCAUTHS_IN:
   3161     XPREPARE ("select_above_serial_by_table_kycauth_in",
   3162               "SELECT"
   3163               " kycauth_in_serial_id AS serial"
   3164               ",account_pub"
   3165               ",wire_reference"
   3166               ",credit"
   3167               ",wire_source_h_payto"
   3168               ",exchange_account_section"
   3169               ",execution_date"
   3170               " FROM kycauths_in"
   3171               " WHERE kycauth_in_serial_id > $1"
   3172               " ORDER BY kycauth_in_serial_id ASC;");
   3173     rh = &lrbt_cb_table_kycauth_in;
   3174     break;
   3175   case TALER_EXCHANGEDB_RT_RESERVES_CLOSE:
   3176     XPREPARE ("select_above_serial_by_table_reserves_close",
   3177               "SELECT"
   3178               " close_uuid AS serial"
   3179               ",reserve_pub"
   3180               ",execution_date"
   3181               ",wtid"
   3182               ",wire_target_h_payto"
   3183               ",amount"
   3184               ",closing_fee"
   3185               " FROM reserves_close"
   3186               " WHERE close_uuid > $1"
   3187               " ORDER BY close_uuid ASC;");
   3188     rh = &lrbt_cb_table_reserves_close;
   3189     break;
   3190   case TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS:
   3191     XPREPARE ("select_above_serial_by_table_reserves_open_requests",
   3192               "SELECT"
   3193               " open_request_uuid AS serial"
   3194               ",reserve_pub"
   3195               ",request_timestamp"
   3196               ",expiration_date"
   3197               ",reserve_sig"
   3198               ",reserve_payment"
   3199               ",requested_purse_limit"
   3200               " FROM reserves_open_requests"
   3201               " WHERE open_request_uuid > $1"
   3202               " ORDER BY open_request_uuid ASC;");
   3203     rh = &lrbt_cb_table_reserves_open_requests;
   3204     break;
   3205   case TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS:
   3206     XPREPARE ("select_above_serial_by_table_reserves_open_deposits",
   3207               "SELECT"
   3208               " reserves_open_deposit_uuid AS serial"
   3209               ",reserve_sig"
   3210               ",reserve_pub"
   3211               ",coin_pub"
   3212               ",coin_sig"
   3213               ",contribution"
   3214               " FROM reserves_open_deposits"
   3215               " WHERE reserves_open_deposit_uuid > $1"
   3216               " ORDER BY reserves_open_deposit_uuid ASC;");
   3217     rh = &lrbt_cb_table_reserves_open_deposits;
   3218     break;
   3219   case TALER_EXCHANGEDB_RT_AUDITORS:
   3220     XPREPARE ("select_above_serial_by_table_auditors",
   3221               "SELECT"
   3222               " auditor_uuid AS serial"
   3223               ",auditor_pub"
   3224               ",auditor_name"
   3225               ",auditor_url"
   3226               ",is_active"
   3227               ",last_change"
   3228               " FROM auditors"
   3229               " WHERE auditor_uuid > $1"
   3230               " ORDER BY auditor_uuid ASC;");
   3231     rh = &lrbt_cb_table_auditors;
   3232     break;
   3233   case TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS:
   3234     XPREPARE ("select_above_serial_by_table_auditor_denom_sigs",
   3235               "SELECT"
   3236               " auditor_denom_serial AS serial"
   3237               ",auditor_uuid"
   3238               ",denominations_serial"
   3239               ",auditor_sig"
   3240               " FROM auditor_denom_sigs"
   3241               " WHERE auditor_denom_serial > $1"
   3242               " ORDER BY auditor_denom_serial ASC;");
   3243     rh = &lrbt_cb_table_auditor_denom_sigs;
   3244     break;
   3245   case TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS:
   3246     XPREPARE ("select_above_serial_by_table_exchange_sign_keys",
   3247               "SELECT"
   3248               " esk_serial AS serial"
   3249               ",exchange_pub"
   3250               ",master_sig"
   3251               ",valid_from"
   3252               ",expire_sign"
   3253               ",expire_legal"
   3254               " FROM exchange_sign_keys"
   3255               " WHERE esk_serial > $1"
   3256               " ORDER BY esk_serial ASC;");
   3257     rh = &lrbt_cb_table_exchange_sign_keys;
   3258     break;
   3259   case TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS:
   3260     XPREPARE ("select_above_serial_by_table_signkey_revocations",
   3261               "SELECT"
   3262               " signkey_revocations_serial_id AS serial"
   3263               ",esk_serial"
   3264               ",master_sig"
   3265               " FROM signkey_revocations"
   3266               " WHERE signkey_revocations_serial_id > $1"
   3267               " ORDER BY signkey_revocations_serial_id ASC;");
   3268     rh = &lrbt_cb_table_signkey_revocations;
   3269     break;
   3270   case TALER_EXCHANGEDB_RT_KNOWN_COINS:
   3271     XPREPARE ("select_above_serial_by_table_known_coins",
   3272               "SELECT"
   3273               " known_coin_id AS serial"
   3274               ",coin_pub"
   3275               ",denom_sig"
   3276               ",denominations_serial"
   3277               " FROM known_coins"
   3278               " WHERE known_coin_id > $1"
   3279               " ORDER BY known_coin_id ASC;");
   3280     rh = &lrbt_cb_table_known_coins;
   3281     break;
   3282   case TALER_EXCHANGEDB_RT_REFRESH:
   3283     XPREPARE ("select_above_serial_by_table_refresh",
   3284               "SELECT"
   3285               " refresh_id AS serial"
   3286               ",rc"
   3287               ",execution_date"
   3288               ",amount_with_fee"
   3289               ",old_coin_pub"
   3290               ",old_coin_sig"
   3291               ",refresh_seed"
   3292               ",noreveal_index"
   3293               ",planchets_h"
   3294               ",selected_h"
   3295               ",blinding_seed"
   3296               ",cs_r_values"
   3297               ",cs_r_choices"
   3298               ",denom_serials"
   3299               ",denom_sigs"
   3300               " FROM refresh"
   3301               " WHERE refresh_id > $1"
   3302               " ORDER BY refresh_id ASC;");
   3303     rh = &lrbt_cb_table_refresh;
   3304     break;
   3305   case TALER_EXCHANGEDB_RT_BATCH_DEPOSITS:
   3306     XPREPARE ("select_above_serial_by_table_batch_deposits",
   3307               "SELECT"
   3308               " batch_deposit_serial_id AS serial"
   3309               ",shard"
   3310               ",merchant_pub"
   3311               ",wallet_timestamp"
   3312               ",exchange_timestamp"
   3313               ",refund_deadline"
   3314               ",wire_deadline"
   3315               ",h_contract_terms"
   3316               ",wallet_data_hash"
   3317               ",wire_salt"
   3318               ",wire_target_h_payto"
   3319               ",policy_details_serial_id"
   3320               ",policy_blocked"
   3321               ",total_amount"
   3322               ",total_without_fee"
   3323               ",merchant_sig"
   3324               ",done"
   3325               " FROM batch_deposits"
   3326               " WHERE batch_deposit_serial_id > $1"
   3327               " ORDER BY batch_deposit_serial_id ASC;");
   3328     rh = &lrbt_cb_table_batch_deposits;
   3329     break;
   3330   case TALER_EXCHANGEDB_RT_COIN_DEPOSITS:
   3331     XPREPARE ("select_above_serial_by_table_coin_deposits",
   3332               "SELECT"
   3333               " coin_deposit_serial_id AS serial"
   3334               ",batch_deposit_serial_id"
   3335               ",coin_pub"
   3336               ",coin_sig"
   3337               ",amount_with_fee"
   3338               " FROM coin_deposits"
   3339               " WHERE coin_deposit_serial_id > $1"
   3340               " ORDER BY coin_deposit_serial_id ASC;");
   3341     rh = &lrbt_cb_table_coin_deposits;
   3342     break;
   3343   case TALER_EXCHANGEDB_RT_REFUNDS:
   3344     XPREPARE ("select_above_serial_by_table_refunds",
   3345               "SELECT"
   3346               " refund_serial_id AS serial"
   3347               ",coin_pub"
   3348               ",merchant_sig"
   3349               ",rtransaction_id"
   3350               ",amount_with_fee"
   3351               ",batch_deposit_serial_id"
   3352               " FROM refunds"
   3353               " WHERE refund_serial_id > $1"
   3354               " ORDER BY refund_serial_id ASC;");
   3355     rh = &lrbt_cb_table_refunds;
   3356     break;
   3357   case TALER_EXCHANGEDB_RT_WIRE_OUT:
   3358     XPREPARE ("select_above_serial_by_table_wire_out",
   3359               "SELECT"
   3360               " wireout_uuid AS serial"
   3361               ",execution_date"
   3362               ",wtid_raw"
   3363               ",wire_target_h_payto"
   3364               ",exchange_account_section"
   3365               ",amount"
   3366               " FROM wire_out"
   3367               " WHERE wireout_uuid > $1"
   3368               " ORDER BY wireout_uuid ASC;");
   3369     rh = &lrbt_cb_table_wire_out;
   3370     break;
   3371   case TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING:
   3372     XPREPARE ("select_above_serial_by_table_aggregation_tracking",
   3373               "SELECT"
   3374               " aggregation_serial_id AS serial"
   3375               ",batch_deposit_serial_id"
   3376               ",wtid_raw"
   3377               " FROM aggregation_tracking"
   3378               " WHERE aggregation_serial_id > $1"
   3379               " ORDER BY aggregation_serial_id ASC;");
   3380     rh = &lrbt_cb_table_aggregation_tracking;
   3381     break;
   3382   case TALER_EXCHANGEDB_RT_WIRE_FEE:
   3383     XPREPARE ("select_above_serial_by_table_wire_fee",
   3384               "SELECT"
   3385               " wire_fee_serial AS serial"
   3386               ",wire_method"
   3387               ",start_date"
   3388               ",end_date"
   3389               ",wire_fee"
   3390               ",closing_fee"
   3391               ",master_sig"
   3392               " FROM wire_fee"
   3393               " WHERE wire_fee_serial > $1"
   3394               " ORDER BY wire_fee_serial ASC;");
   3395     rh = &lrbt_cb_table_wire_fee;
   3396     break;
   3397   case TALER_EXCHANGEDB_RT_GLOBAL_FEE:
   3398     XPREPARE ("select_above_serial_by_table_global_fee",
   3399               "SELECT"
   3400               " global_fee_serial AS serial"
   3401               ",start_date"
   3402               ",end_date"
   3403               ",history_fee"
   3404               ",account_fee"
   3405               ",purse_fee"
   3406               ",purse_timeout"
   3407               ",history_expiration"
   3408               ",purse_account_limit"
   3409               ",master_sig"
   3410               " FROM global_fee"
   3411               " WHERE global_fee_serial > $1"
   3412               " ORDER BY global_fee_serial ASC;");
   3413     rh = &lrbt_cb_table_global_fee;
   3414     break;
   3415   case TALER_EXCHANGEDB_RT_RECOUP:
   3416     XPREPARE ("select_above_serial_by_table_recoup",
   3417               "SELECT"
   3418               " recoup_uuid AS serial"
   3419               ",coin_sig"
   3420               ",coin_blind"
   3421               ",amount"
   3422               ",recoup_timestamp"
   3423               ",coin_pub"
   3424               ",reserve_out_serial_id"
   3425               " FROM recoup"
   3426               " WHERE recoup_uuid > $1"
   3427               " ORDER BY recoup_uuid ASC;");
   3428     rh = &lrbt_cb_table_recoup;
   3429     break;
   3430   case TALER_EXCHANGEDB_RT_RECOUP_REFRESH:
   3431     XPREPARE ("select_above_serial_by_table_recoup_refresh",
   3432               "SELECT"
   3433               " recoup_refresh_uuid AS serial"
   3434               ",coin_sig"
   3435               ",coin_blind"
   3436               ",amount"
   3437               ",recoup_timestamp"
   3438               ",coin_pub"
   3439               ",known_coin_id"
   3440               ",rrc_serial"
   3441               " FROM recoup_refresh"
   3442               " WHERE recoup_refresh_uuid > $1"
   3443               " ORDER BY recoup_refresh_uuid ASC;");
   3444     rh = &lrbt_cb_table_recoup_refresh;
   3445     break;
   3446   case TALER_EXCHANGEDB_RT_EXTENSIONS:
   3447     // FIXME: this seems broken! -- where is the SQL!?
   3448     statement = "select_above_serial_by_table_extensions";
   3449     rh = &lrbt_cb_table_extensions;
   3450     break;
   3451   case TALER_EXCHANGEDB_RT_POLICY_DETAILS:
   3452     // FIXME: this seems broken! -- where is the SQL!?
   3453     statement = "select_above_serial_by_table_policy_details";
   3454     rh = &lrbt_cb_table_policy_details;
   3455     break;
   3456   case TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS:
   3457     // FIXME: this seems broken! -- where is the SQL!?
   3458     statement = "select_above_serial_by_table_policy_fulfillments";
   3459     rh = &lrbt_cb_table_policy_fulfillments;
   3460     break;
   3461   case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
   3462     XPREPARE ("select_above_serial_by_table_purse_requests",
   3463               "SELECT"
   3464               " purse_requests_serial_id"
   3465               ",purse_pub"
   3466               ",merge_pub"
   3467               ",purse_creation"
   3468               ",purse_expiration"
   3469               ",h_contract_terms"
   3470               ",age_limit"
   3471               ",flags"
   3472               ",amount_with_fee"
   3473               ",purse_fee"
   3474               ",purse_sig"
   3475               " FROM purse_requests"
   3476               " WHERE purse_requests_serial_id > $1"
   3477               " ORDER BY purse_requests_serial_id ASC;");
   3478     rh = &lrbt_cb_table_purse_requests;
   3479     break;
   3480   case TALER_EXCHANGEDB_RT_PURSE_DECISION:
   3481     XPREPARE ("select_above_serial_by_table_purse_decision",
   3482               "SELECT"
   3483               " purse_decision_serial_id"
   3484               ",action_timestamp"
   3485               ",refunded"
   3486               ",purse_pub"
   3487               " FROM purse_decision"
   3488               " WHERE purse_decision_serial_id > $1"
   3489               " ORDER BY purse_decision_serial_id ASC;");
   3490     rh = &lrbt_cb_table_purse_decision;
   3491     break;
   3492   case TALER_EXCHANGEDB_RT_PURSE_MERGES:
   3493     XPREPARE ("select_above_serial_by_table_purse_merges",
   3494               "SELECT"
   3495               " purse_merge_request_serial_id"
   3496               ",partner_serial_id"
   3497               ",reserve_pub"
   3498               ",purse_pub"
   3499               ",merge_sig"
   3500               ",merge_timestamp"
   3501               " FROM purse_merges"
   3502               " WHERE purse_merge_request_serial_id > $1"
   3503               " ORDER BY purse_merge_request_serial_id ASC;");
   3504     rh = &lrbt_cb_table_purse_merges;
   3505     break;
   3506   case TALER_EXCHANGEDB_RT_PURSE_DEPOSITS:
   3507     XPREPARE ("select_above_serial_by_table_purse_deposits",
   3508               "SELECT"
   3509               " purse_deposit_serial_id"
   3510               ",partner_serial_id"
   3511               ",purse_pub"
   3512               ",coin_pub"
   3513               ",amount_with_fee"
   3514               ",coin_sig"
   3515               " FROM purse_deposits"
   3516               " WHERE purse_deposit_serial_id > $1"
   3517               " ORDER BY purse_deposit_serial_id ASC;");
   3518     rh = &lrbt_cb_table_purse_deposits;
   3519     break;
   3520   case TALER_EXCHANGEDB_RT_ACCOUNT_MERGES:
   3521     XPREPARE ("select_above_serial_by_table_account_merges",
   3522               "SELECT"
   3523               " account_merge_request_serial_id"
   3524               ",reserve_pub"
   3525               ",reserve_sig"
   3526               ",purse_pub"
   3527               ",wallet_h_payto"
   3528               " FROM account_merges"
   3529               " WHERE account_merge_request_serial_id > $1"
   3530               " ORDER BY account_merge_request_serial_id ASC;");
   3531     rh = &lrbt_cb_table_account_merges;
   3532     break;
   3533   case TALER_EXCHANGEDB_RT_HISTORY_REQUESTS:
   3534     XPREPARE ("select_above_serial_by_table_history_requests",
   3535               "SELECT"
   3536               " history_request_serial_id"
   3537               ",reserve_pub"
   3538               ",request_timestamp"
   3539               ",reserve_sig"
   3540               ",history_fee"
   3541               " FROM history_requests"
   3542               " WHERE history_request_serial_id > $1"
   3543               " ORDER BY history_request_serial_id ASC;");
   3544     rh = &lrbt_cb_table_history_requests;
   3545     break;
   3546   case TALER_EXCHANGEDB_RT_CLOSE_REQUESTS:
   3547     XPREPARE ("select_above_serial_by_table_close_requests",
   3548               "SELECT"
   3549               " close_request_serial_id"
   3550               ",reserve_pub"
   3551               ",close_timestamp"
   3552               ",reserve_sig"
   3553               ",close"
   3554               " FROM close_requests"
   3555               " WHERE close_request_serial_id > $1"
   3556               " ORDER BY close_request_serial_id ASC;");
   3557     rh = &lrbt_cb_table_close_requests;
   3558     break;
   3559   case TALER_EXCHANGEDB_RT_WADS_OUT:
   3560     XPREPARE ("select_above_serial_by_table_wads_out",
   3561               "SELECT"
   3562               " wad_out_serial_id"
   3563               ",wad_id"
   3564               ",partner_serial_id"
   3565               ",amount"
   3566               ",execution_time"
   3567               " FROM wads_out"
   3568               " WHERE wad_out_serial_id > $1"
   3569               " ORDER BY wad_out_serial_id ASC;");
   3570     rh = &lrbt_cb_table_wads_out;
   3571     break;
   3572   case TALER_EXCHANGEDB_RT_WADS_OUT_ENTRIES:
   3573     XPREPARE ("select_above_serial_by_table_wads_out_entries",
   3574               "SELECT"
   3575               " wad_out_entry_serial_id"
   3576               ",reserve_pub"
   3577               ",purse_pub"
   3578               ",h_contract"
   3579               ",purse_expiration"
   3580               ",merge_timestamp"
   3581               ",amount_with_fee"
   3582               ",wad_fee"
   3583               ",deposit_fees"
   3584               ",reserve_sig"
   3585               ",purse_sig"
   3586               " FROM wad_out_entries"
   3587               " WHERE wad_out_entry_serial_id > $1"
   3588               " ORDER BY wad_out_entry_serial_id ASC;");
   3589     rh = &lrbt_cb_table_wads_out_entries;
   3590     break;
   3591   case TALER_EXCHANGEDB_RT_WADS_IN:
   3592     XPREPARE ("select_above_serial_by_table_wads_in",
   3593               "SELECT"
   3594               " wad_in_serial_id"
   3595               ",wad_id"
   3596               ",origin_exchange_url"
   3597               ",amount"
   3598               ",arrival_time"
   3599               " FROM wads_in"
   3600               " WHERE wad_in_serial_id > $1"
   3601               " ORDER BY wad_in_serial_id ASC;");
   3602     rh = &lrbt_cb_table_wads_in;
   3603     break;
   3604   case TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES:
   3605     XPREPARE ("select_above_serial_by_table_wads_in_entries",
   3606               "SELECT"
   3607               " wad_in_entry_serial_id"
   3608               ",reserve_pub"
   3609               ",purse_pub"
   3610               ",h_contract"
   3611               ",purse_expiration"
   3612               ",merge_timestamp"
   3613               ",amount_with_fee"
   3614               ",wad_fee"
   3615               ",deposit_fees"
   3616               ",reserve_sig"
   3617               ",purse_sig"
   3618               " FROM wad_in_entries"
   3619               " WHERE wad_in_entry_serial_id > $1"
   3620               " ORDER BY wad_in_entry_serial_id ASC;");
   3621     rh = &lrbt_cb_table_wads_in_entries;
   3622     break;
   3623   case TALER_EXCHANGEDB_RT_PROFIT_DRAINS:
   3624     XPREPARE ("select_above_serial_by_table_profit_drains",
   3625               "SELECT"
   3626               " profit_drain_serial_id"
   3627               ",wtid"
   3628               ",account_section"
   3629               ",payto_uri"
   3630               ",trigger_date"
   3631               ",amount"
   3632               ",master_sig"
   3633               " FROM profit_drains"
   3634               " WHERE profit_drain_serial_id > $1"
   3635               " ORDER BY profit_drain_serial_id ASC;");
   3636     rh = &lrbt_cb_table_profit_drains;
   3637     break;
   3638 
   3639   case TALER_EXCHANGEDB_RT_AML_STAFF:
   3640     XPREPARE ("select_above_serial_by_table_aml_staff",
   3641               "SELECT"
   3642               " aml_staff_uuid"
   3643               ",decider_pub"
   3644               ",master_sig"
   3645               ",decider_name"
   3646               ",is_active"
   3647               ",read_only"
   3648               ",last_change"
   3649               " FROM aml_staff"
   3650               " WHERE aml_staff_uuid > $1"
   3651               " ORDER BY aml_staff_uuid ASC;");
   3652     rh = &lrbt_cb_table_aml_staff;
   3653     break;
   3654   case TALER_EXCHANGEDB_RT_PURSE_DELETION:
   3655     XPREPARE ("select_above_serial_by_table_purse_deletion",
   3656               "SELECT"
   3657               " purse_deletion_serial_id"
   3658               ",purse_pub"
   3659               ",purse_sig"
   3660               " FROM purse_deletion"
   3661               " WHERE purse_deletion_serial_id > $1"
   3662               " ORDER BY purse_deletion_serial_id ASC;");
   3663     rh = &lrbt_cb_table_purse_deletion;
   3664     break;
   3665   case TALER_EXCHANGEDB_RT_WITHDRAW:
   3666     XPREPARE ("select_above_serial_by_table_withdraw",
   3667               "SELECT"
   3668               " withdraw_id"
   3669               ",planchets_h"
   3670               ",execution_date"
   3671               ",amount_with_fee"
   3672               ",reserve_pub"
   3673               ",reserve_sig"
   3674               ",max_age"
   3675               ",noreveal_index"
   3676               ",selected_h"
   3677               ",blinding_seed"
   3678               ",cs_r_values"
   3679               ",cs_r_choices"
   3680               ",denom_serials"
   3681               ",denom_sigs"
   3682               " FROM withdraw"
   3683               " WHERE withdraw_id > $1"
   3684               " ORDER BY withdraw_id ASC;");
   3685     rh = &lrbt_cb_table_withdraw;
   3686     break;
   3687   case TALER_EXCHANGEDB_RT_LEGITIMIZATION_MEASURES:
   3688     XPREPARE ("select_above_serial_by_table_legitimization_measures",
   3689               "SELECT"
   3690               " legitimization_measure_serial_id AS serial"
   3691               ",access_token"
   3692               ",start_time"
   3693               ",jmeasures::TEXT"
   3694               ",display_priority"
   3695               " FROM legitimization_measures"
   3696               " WHERE legitimization_measure_serial_id > $1"
   3697               " ORDER BY legitimization_measure_serial_id ASC;");
   3698     rh = &lrbt_cb_table_legitimization_measures;
   3699     break;
   3700   case TALER_EXCHANGEDB_RT_LEGITIMIZATION_OUTCOMES:
   3701     XPREPARE ("select_above_serial_by_table_legitimization_outcomes",
   3702               "SELECT"
   3703               " outcome_serial_id AS serial"
   3704               ",h_payto"
   3705               ",decision_time"
   3706               ",expiration_time"
   3707               ",jproperties::TEXT"
   3708               ",to_investigate"
   3709               ",jnew_rules::TEXT"
   3710               " FROM legitimization_outcomes"
   3711               " WHERE outcome_serial_id > $1"
   3712               " ORDER BY outcome_serial_id ASC;");
   3713     rh = &lrbt_cb_table_legitimization_outcomes;
   3714     break;
   3715   case TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES:
   3716     XPREPARE ("select_above_serial_by_table_legitimization_processes",
   3717               "SELECT"
   3718               " legitimization_process_serial_id AS serial"
   3719               ",h_payto"
   3720               ",start_time"
   3721               ",expiration_time"
   3722               ",legitimization_measure_serial_id"
   3723               ",measure_index"
   3724               ",provider_name"
   3725               ",provider_user_id"
   3726               ",provider_legitimization_id"
   3727               ",redirect_url"
   3728               " FROM legitimization_processes"
   3729               " WHERE legitimization_process_serial_id > $1"
   3730               " ORDER BY legitimization_process_serial_id ASC;");
   3731     rh = &lrbt_cb_table_legitimization_processes;
   3732     break;
   3733   case TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES:
   3734     XPREPARE ("select_above_serial_by_table_kyc_attributes",
   3735               "SELECT"
   3736               " kyc_attributes_serial_id"
   3737               ",h_payto"
   3738               ",legitimization_serial"
   3739               ",collection_time"
   3740               ",expiration_time"
   3741               ",trigger_outcome_serial"
   3742               ",encrypted_attributes"
   3743               " FROM kyc_attributes"
   3744               " WHERE kyc_attributes_serial_id > $1"
   3745               " ORDER BY kyc_attributes_serial_id ASC;");
   3746     rh = &lrbt_cb_table_kyc_attributes;
   3747     break;
   3748   case TALER_EXCHANGEDB_RT_AML_HISTORY:
   3749     XPREPARE ("select_above_serial_by_table_aml_history",
   3750               "SELECT"
   3751               " aml_history_serial_id"
   3752               ",h_payto"
   3753               ",outcome_serial_id"
   3754               ",justification"
   3755               ",decider_pub"
   3756               ",decider_sig"
   3757               " FROM aml_history"
   3758               " WHERE aml_history_serial_id > $1"
   3759               " ORDER BY aml_history_serial_id ASC;");
   3760     rh = &lrbt_cb_table_aml_history;
   3761     break;
   3762   case TALER_EXCHANGEDB_RT_KYC_EVENTS:
   3763     XPREPARE ("select_above_serial_by_table_kyc_events",
   3764               "SELECT"
   3765               " kyc_event_serial_id AS serial"
   3766               ",event_timestamp"
   3767               ",event_type"
   3768               " FROM kyc_events"
   3769               " WHERE kyc_event_serial_id > $1"
   3770               " ORDER BY kyc_event_serial_id ASC;");
   3771     rh = &lrbt_cb_table_kyc_events;
   3772     break;
   3773   }
   3774   if (NULL == rh)
   3775   {
   3776     GNUNET_break (0);
   3777     return GNUNET_DB_STATUS_HARD_ERROR;
   3778   }
   3779 
   3780   qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
   3781                                              statement,
   3782                                              params,
   3783                                              rh,
   3784                                              &ctx);
   3785   if (qs < 0)
   3786   {
   3787     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3788                 "Failed to run `%s'\n",
   3789                 statement);
   3790     return qs;
   3791   }
   3792   if (ctx.error)
   3793   {
   3794     GNUNET_break (0);
   3795     return GNUNET_DB_STATUS_HARD_ERROR;
   3796   }
   3797   return qs;
   3798 }
   3799 
   3800 
   3801 #undef XPREPARE
   3802 
   3803 /* end of pg_lookup_records_by_table.c */