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 (115227B)


      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       GNUNET_PQ_result_spec_auto_from_type (
   1065         "merchant_sig",
   1066         &td.details.batch_deposits.merchant_sig),
   1067       GNUNET_PQ_result_spec_bool (
   1068         "done",
   1069         &td.details.batch_deposits.done),
   1070       GNUNET_PQ_result_spec_end
   1071     };
   1072 
   1073     td.details.batch_deposits.policy_details_serial_id = 0;
   1074     if (GNUNET_OK !=
   1075         GNUNET_PQ_extract_result (result,
   1076                                   rs,
   1077                                   i))
   1078     {
   1079       GNUNET_break (0);
   1080       ctx->error = true;
   1081       return;
   1082     }
   1083     ctx->cb (ctx->cb_cls,
   1084              &td);
   1085     GNUNET_PQ_cleanup_result (rs);
   1086   }
   1087 }
   1088 
   1089 
   1090 /**
   1091  * Function called with coin deposits table entries.
   1092  *
   1093  * @param cls closure
   1094  * @param result the postgres result
   1095  * @param num_results the number of results in @a result
   1096  */
   1097 static void
   1098 lrbt_cb_table_coin_deposits (void *cls,
   1099                              PGresult *result,
   1100                              unsigned int num_results)
   1101 {
   1102   struct LookupRecordsByTableContext *ctx = cls;
   1103   struct PostgresClosure *pg = ctx->pg;
   1104   struct TALER_EXCHANGEDB_TableData td = {
   1105     .table = TALER_EXCHANGEDB_RT_COIN_DEPOSITS
   1106   };
   1107 
   1108   for (unsigned int i = 0; i<num_results; i++)
   1109   {
   1110     struct GNUNET_PQ_ResultSpec rs[] = {
   1111       GNUNET_PQ_result_spec_uint64 (
   1112         "serial",
   1113         &td.serial),
   1114       GNUNET_PQ_result_spec_uint64 (
   1115         "batch_deposit_serial_id",
   1116         &td.details.coin_deposits.batch_deposit_serial_id),
   1117       GNUNET_PQ_result_spec_auto_from_type (
   1118         "coin_pub",
   1119         &td.details.coin_deposits.coin_pub),
   1120       GNUNET_PQ_result_spec_auto_from_type (
   1121         "coin_sig",
   1122         &td.details.coin_deposits.coin_sig),
   1123       TALER_PQ_RESULT_SPEC_AMOUNT (
   1124         "amount_with_fee",
   1125         &td.details.coin_deposits.amount_with_fee),
   1126       GNUNET_PQ_result_spec_end
   1127     };
   1128 
   1129     if (GNUNET_OK !=
   1130         GNUNET_PQ_extract_result (result,
   1131                                   rs,
   1132                                   i))
   1133     {
   1134       GNUNET_break (0);
   1135       ctx->error = true;
   1136       return;
   1137     }
   1138     ctx->cb (ctx->cb_cls,
   1139              &td);
   1140     GNUNET_PQ_cleanup_result (rs);
   1141   }
   1142 }
   1143 
   1144 
   1145 /**
   1146  * Function called with refunds table entries.
   1147  *
   1148  * @param cls closure
   1149  * @param result the postgres result
   1150  * @param num_results the number of results in @a result
   1151  */
   1152 static void
   1153 lrbt_cb_table_refunds (void *cls,
   1154                        PGresult *result,
   1155                        unsigned int num_results)
   1156 {
   1157   struct LookupRecordsByTableContext *ctx = cls;
   1158   struct PostgresClosure *pg = ctx->pg;
   1159   struct TALER_EXCHANGEDB_TableData td = {
   1160     .table = TALER_EXCHANGEDB_RT_REFUNDS
   1161   };
   1162 
   1163   for (unsigned int i = 0; i<num_results; i++)
   1164   {
   1165     struct GNUNET_PQ_ResultSpec rs[] = {
   1166       GNUNET_PQ_result_spec_uint64 (
   1167         "serial",
   1168         &td.serial),
   1169       GNUNET_PQ_result_spec_auto_from_type (
   1170         "coin_pub",
   1171         &td.details.refunds.coin_pub),
   1172       GNUNET_PQ_result_spec_auto_from_type (
   1173         "merchant_sig",
   1174         &td.details.refunds.merchant_sig),
   1175       GNUNET_PQ_result_spec_uint64 (
   1176         "rtransaction_id",
   1177         &td.details.refunds.rtransaction_id),
   1178       TALER_PQ_RESULT_SPEC_AMOUNT (
   1179         "amount_with_fee",
   1180         &td.details.refunds.amount_with_fee),
   1181       GNUNET_PQ_result_spec_uint64 (
   1182         "batch_deposit_serial_id",
   1183         &td.details.refunds.batch_deposit_serial_id),
   1184       GNUNET_PQ_result_spec_end
   1185     };
   1186 
   1187     if (GNUNET_OK !=
   1188         GNUNET_PQ_extract_result (result,
   1189                                   rs,
   1190                                   i))
   1191     {
   1192       GNUNET_break (0);
   1193       ctx->error = true;
   1194       return;
   1195     }
   1196     ctx->cb (ctx->cb_cls,
   1197              &td);
   1198     GNUNET_PQ_cleanup_result (rs);
   1199   }
   1200 }
   1201 
   1202 
   1203 /**
   1204  * Function called with wire_out table entries.
   1205  *
   1206  * @param cls closure
   1207  * @param result the postgres result
   1208  * @param num_results the number of results in @a result
   1209  */
   1210 static void
   1211 lrbt_cb_table_wire_out (void *cls,
   1212                         PGresult *result,
   1213                         unsigned int num_results)
   1214 {
   1215   struct LookupRecordsByTableContext *ctx = cls;
   1216   struct PostgresClosure *pg = ctx->pg;
   1217   struct TALER_EXCHANGEDB_TableData td = {
   1218     .table = TALER_EXCHANGEDB_RT_WIRE_OUT
   1219   };
   1220 
   1221   for (unsigned int i = 0; i<num_results; i++)
   1222   {
   1223     struct GNUNET_PQ_ResultSpec rs[] = {
   1224       GNUNET_PQ_result_spec_uint64 ("serial",
   1225                                     &td.serial),
   1226       GNUNET_PQ_result_spec_timestamp (
   1227         "execution_date",
   1228         &td.details.wire_out.execution_date),
   1229       GNUNET_PQ_result_spec_auto_from_type (
   1230         "wtid_raw",
   1231         &td.details.wire_out.wtid_raw),
   1232       GNUNET_PQ_result_spec_auto_from_type (
   1233         "wire_target_h_payto",
   1234         &td.details.wire_out.wire_target_h_payto),
   1235       GNUNET_PQ_result_spec_string (
   1236         "exchange_account_section",
   1237         &td.details.wire_out.exchange_account_section),
   1238       TALER_PQ_RESULT_SPEC_AMOUNT (
   1239         "amount",
   1240         &td.details.wire_out.amount),
   1241       GNUNET_PQ_result_spec_end
   1242     };
   1243 
   1244     if (GNUNET_OK !=
   1245         GNUNET_PQ_extract_result (result,
   1246                                   rs,
   1247                                   i))
   1248     {
   1249       GNUNET_break (0);
   1250       ctx->error = true;
   1251       return;
   1252     }
   1253     ctx->cb (ctx->cb_cls,
   1254              &td);
   1255     GNUNET_PQ_cleanup_result (rs);
   1256   }
   1257 }
   1258 
   1259 
   1260 /**
   1261  * Function called with aggregation_tracking table entries.
   1262  *
   1263  * @param cls closure
   1264  * @param result the postgres result
   1265  * @param num_results the number of results in @a result
   1266  */
   1267 static void
   1268 lrbt_cb_table_aggregation_tracking (void *cls,
   1269                                     PGresult *result,
   1270                                     unsigned int num_results)
   1271 {
   1272   struct LookupRecordsByTableContext *ctx = cls;
   1273   struct TALER_EXCHANGEDB_TableData td = {
   1274     .table = TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING
   1275   };
   1276 
   1277   for (unsigned int i = 0; i<num_results; i++)
   1278   {
   1279     struct GNUNET_PQ_ResultSpec rs[] = {
   1280       GNUNET_PQ_result_spec_uint64 (
   1281         "serial",
   1282         &td.serial),
   1283       GNUNET_PQ_result_spec_uint64 (
   1284         "batch_deposit_serial_id",
   1285         &td.details.aggregation_tracking.batch_deposit_serial_id),
   1286       GNUNET_PQ_result_spec_auto_from_type (
   1287         "wtid_raw",
   1288         &td.details.aggregation_tracking.wtid_raw),
   1289       GNUNET_PQ_result_spec_end
   1290     };
   1291 
   1292     if (GNUNET_OK !=
   1293         GNUNET_PQ_extract_result (result,
   1294                                   rs,
   1295                                   i))
   1296     {
   1297       GNUNET_break (0);
   1298       ctx->error = true;
   1299       return;
   1300     }
   1301     ctx->cb (ctx->cb_cls,
   1302              &td);
   1303     GNUNET_PQ_cleanup_result (rs);
   1304   }
   1305 }
   1306 
   1307 
   1308 /**
   1309  * Function called with wire_fee table entries.
   1310  *
   1311  * @param cls closure
   1312  * @param result the postgres result
   1313  * @param num_results the number of results in @a result
   1314  */
   1315 static void
   1316 lrbt_cb_table_wire_fee (void *cls,
   1317                         PGresult *result,
   1318                         unsigned int num_results)
   1319 {
   1320   struct LookupRecordsByTableContext *ctx = cls;
   1321   struct PostgresClosure *pg = ctx->pg;
   1322   struct TALER_EXCHANGEDB_TableData td = {
   1323     .table = TALER_EXCHANGEDB_RT_WIRE_FEE
   1324   };
   1325 
   1326   for (unsigned int i = 0; i<num_results; i++)
   1327   {
   1328     struct GNUNET_PQ_ResultSpec rs[] = {
   1329       GNUNET_PQ_result_spec_uint64 ("serial",
   1330                                     &td.serial),
   1331       GNUNET_PQ_result_spec_string ("wire_method",
   1332                                     &td.details.wire_fee.wire_method),
   1333       GNUNET_PQ_result_spec_timestamp ("start_date",
   1334                                        &td.details.wire_fee.start_date),
   1335       GNUNET_PQ_result_spec_timestamp ("end_date",
   1336                                        &td.details.wire_fee.end_date),
   1337       TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
   1338                                    &td.details.wire_fee.fees.wire),
   1339       TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
   1340                                    &td.details.wire_fee.fees.closing),
   1341       GNUNET_PQ_result_spec_auto_from_type ("master_sig",
   1342                                             &td.details.wire_fee.master_sig),
   1343       GNUNET_PQ_result_spec_end
   1344     };
   1345 
   1346     if (GNUNET_OK !=
   1347         GNUNET_PQ_extract_result (result,
   1348                                   rs,
   1349                                   i))
   1350     {
   1351       GNUNET_break (0);
   1352       ctx->error = true;
   1353       return;
   1354     }
   1355     ctx->cb (ctx->cb_cls,
   1356              &td);
   1357     GNUNET_PQ_cleanup_result (rs);
   1358   }
   1359 }
   1360 
   1361 
   1362 /**
   1363  * Function called with wire_fee table entries.
   1364  *
   1365  * @param cls closure
   1366  * @param result the postgres result
   1367  * @param num_results the number of results in @a result
   1368  */
   1369 static void
   1370 lrbt_cb_table_global_fee (void *cls,
   1371                           PGresult *result,
   1372                           unsigned int num_results)
   1373 {
   1374   struct LookupRecordsByTableContext *ctx = cls;
   1375   struct PostgresClosure *pg = ctx->pg;
   1376   struct TALER_EXCHANGEDB_TableData td = {
   1377     .table = TALER_EXCHANGEDB_RT_GLOBAL_FEE
   1378   };
   1379 
   1380   for (unsigned int i = 0; i<num_results; i++)
   1381   {
   1382     struct GNUNET_PQ_ResultSpec rs[] = {
   1383       GNUNET_PQ_result_spec_uint64 (
   1384         "serial",
   1385         &td.serial),
   1386       GNUNET_PQ_result_spec_timestamp (
   1387         "start_date",
   1388         &td.details.global_fee.start_date),
   1389       GNUNET_PQ_result_spec_timestamp (
   1390         "end_date",
   1391         &td.details.global_fee.end_date),
   1392       TALER_PQ_RESULT_SPEC_AMOUNT (
   1393         "history_fee",
   1394         &td.details.global_fee.fees.history),
   1395       TALER_PQ_RESULT_SPEC_AMOUNT (
   1396         "account_fee",
   1397         &td.details.global_fee.fees.account),
   1398       TALER_PQ_RESULT_SPEC_AMOUNT (
   1399         "purse_fee",
   1400         &td.details.global_fee.fees.purse),
   1401       GNUNET_PQ_result_spec_relative_time (
   1402         "purse_timeout",
   1403         &td.details.global_fee.purse_timeout),
   1404       GNUNET_PQ_result_spec_relative_time (
   1405         "history_expiration",
   1406         &td.details.global_fee.history_expiration),
   1407       GNUNET_PQ_result_spec_uint32 (
   1408         "purse_account_limit",
   1409         &td.details.global_fee.purse_account_limit),
   1410       GNUNET_PQ_result_spec_auto_from_type (
   1411         "master_sig",
   1412         &td.details.global_fee.master_sig),
   1413       GNUNET_PQ_result_spec_end
   1414     };
   1415 
   1416     if (GNUNET_OK !=
   1417         GNUNET_PQ_extract_result (result,
   1418                                   rs,
   1419                                   i))
   1420     {
   1421       GNUNET_break (0);
   1422       ctx->error = true;
   1423       return;
   1424     }
   1425     ctx->cb (ctx->cb_cls,
   1426              &td);
   1427     GNUNET_PQ_cleanup_result (rs);
   1428   }
   1429 }
   1430 
   1431 
   1432 /**
   1433  * Function called with recoup table entries.
   1434  *
   1435  * @param cls closure
   1436  * @param result the postgres result
   1437  * @param num_results the number of results in @a result
   1438  */
   1439 static void
   1440 lrbt_cb_table_recoup (void *cls,
   1441                       PGresult *result,
   1442                       unsigned int num_results)
   1443 {
   1444   struct LookupRecordsByTableContext *ctx = cls;
   1445   struct PostgresClosure *pg = ctx->pg;
   1446   struct TALER_EXCHANGEDB_TableData td = {
   1447     .table = TALER_EXCHANGEDB_RT_RECOUP
   1448   };
   1449 
   1450   for (unsigned int i = 0; i<num_results; i++)
   1451   {
   1452     struct GNUNET_PQ_ResultSpec rs[] = {
   1453       GNUNET_PQ_result_spec_uint64 ("serial",
   1454                                     &td.serial),
   1455       GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
   1456                                             &td.details.recoup.coin_sig),
   1457       GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
   1458                                             &td.details.recoup.coin_blind),
   1459       TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
   1460                                    &td.details.recoup.amount),
   1461       GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
   1462                                        &td.details.recoup.timestamp),
   1463       GNUNET_PQ_result_spec_auto_from_type (
   1464         "coin_pub",
   1465         &td.details.recoup.coin_pub),
   1466       GNUNET_PQ_result_spec_uint64 ("withdraw_serial_id",
   1467                                     &td.details.recoup.withdraw_serial_id),
   1468       GNUNET_PQ_result_spec_end
   1469     };
   1470 
   1471     if (GNUNET_OK !=
   1472         GNUNET_PQ_extract_result (result,
   1473                                   rs,
   1474                                   i))
   1475     {
   1476       GNUNET_break (0);
   1477       ctx->error = true;
   1478       return;
   1479     }
   1480     ctx->cb (ctx->cb_cls,
   1481              &td);
   1482     GNUNET_PQ_cleanup_result (rs);
   1483   }
   1484 }
   1485 
   1486 
   1487 /**
   1488  * Function called with recoup_refresh table entries.
   1489  *
   1490  * @param cls closure
   1491  * @param result the postgres result
   1492  * @param num_results the number of results in @a result
   1493  */
   1494 static void
   1495 lrbt_cb_table_recoup_refresh (void *cls,
   1496                               PGresult *result,
   1497                               unsigned int num_results)
   1498 {
   1499   struct LookupRecordsByTableContext *ctx = cls;
   1500   struct PostgresClosure *pg = ctx->pg;
   1501   struct TALER_EXCHANGEDB_TableData td = {
   1502     .table = TALER_EXCHANGEDB_RT_RECOUP_REFRESH
   1503   };
   1504 
   1505   for (unsigned int i = 0; i<num_results; i++)
   1506   {
   1507     struct GNUNET_PQ_ResultSpec rs[] = {
   1508       GNUNET_PQ_result_spec_uint64 ("serial",
   1509                                     &td.serial),
   1510       GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
   1511                                             &td.details.recoup_refresh.coin_sig)
   1512       ,
   1513       GNUNET_PQ_result_spec_auto_from_type (
   1514         "coin_blind",
   1515         &td.details.recoup_refresh.coin_blind),
   1516       TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
   1517                                    &td.details.recoup_refresh.amount),
   1518       GNUNET_PQ_result_spec_timestamp ("recoup_timestamp",
   1519                                        &td.details.recoup_refresh.timestamp),
   1520       GNUNET_PQ_result_spec_uint64 ("known_coin_id",
   1521                                     &td.details.recoup_refresh.known_coin_id),
   1522       GNUNET_PQ_result_spec_auto_from_type (
   1523         "coin_pub",
   1524         &td.details.recoup_refresh.coin_pub),
   1525       GNUNET_PQ_result_spec_uint64 ("rrc_serial",
   1526                                     &td.details.recoup_refresh.rrc_serial),
   1527       GNUNET_PQ_result_spec_end
   1528     };
   1529 
   1530     if (GNUNET_OK !=
   1531         GNUNET_PQ_extract_result (result,
   1532                                   rs,
   1533                                   i))
   1534     {
   1535       GNUNET_break (0);
   1536       ctx->error = true;
   1537       return;
   1538     }
   1539     ctx->cb (ctx->cb_cls,
   1540              &td);
   1541     GNUNET_PQ_cleanup_result (rs);
   1542   }
   1543 }
   1544 
   1545 
   1546 /**
   1547  * Function called with extensions table entries.
   1548  *
   1549  * @param cls closure
   1550  * @param result the postgres result
   1551  * @param num_results the number of results in @a result
   1552  */
   1553 static void
   1554 lrbt_cb_table_extensions (void *cls,
   1555                           PGresult *result,
   1556                           unsigned int num_results)
   1557 {
   1558   struct LookupRecordsByTableContext *ctx = cls;
   1559   struct TALER_EXCHANGEDB_TableData td = {
   1560     .table = TALER_EXCHANGEDB_RT_EXTENSIONS
   1561   };
   1562   bool no_manifest = false;
   1563 
   1564   for (unsigned int i = 0; i<num_results; i++)
   1565   {
   1566     struct GNUNET_PQ_ResultSpec rs[] = {
   1567       GNUNET_PQ_result_spec_uint64 ("extension_id",
   1568                                     &td.serial),
   1569       GNUNET_PQ_result_spec_string ("name",
   1570                                     &td.details.extensions.name),
   1571       GNUNET_PQ_result_spec_allow_null (
   1572         GNUNET_PQ_result_spec_string ("manifest",
   1573                                       &td.details.extensions.manifest),
   1574         &no_manifest),
   1575       GNUNET_PQ_result_spec_end
   1576     };
   1577 
   1578     if (GNUNET_OK !=
   1579         GNUNET_PQ_extract_result (result,
   1580                                   rs,
   1581                                   i))
   1582     {
   1583       GNUNET_break (0);
   1584       ctx->error = true;
   1585       return;
   1586     }
   1587     ctx->cb (ctx->cb_cls,
   1588              &td);
   1589     GNUNET_PQ_cleanup_result (rs);
   1590   }
   1591 }
   1592 
   1593 
   1594 /**
   1595  * Function called with policy_details table entries.
   1596  *
   1597  * @param cls closure
   1598  * @param result the postgres result
   1599  * @param num_results the number of results in @a result
   1600  */
   1601 static void
   1602 lrbt_cb_table_policy_details (void *cls,
   1603                               PGresult *result,
   1604                               unsigned int num_results)
   1605 {
   1606   struct LookupRecordsByTableContext *ctx = cls;
   1607   struct PostgresClosure *pg = ctx->pg;
   1608   struct TALER_EXCHANGEDB_TableData td = {
   1609     .table = TALER_EXCHANGEDB_RT_POLICY_DETAILS
   1610   };
   1611 
   1612   for (unsigned int i = 0; i<num_results; i++)
   1613   {
   1614     struct GNUNET_PQ_ResultSpec rs[] = {
   1615       GNUNET_PQ_result_spec_uint64 ("policy_details_serial_id",
   1616                                     &td.serial),
   1617       GNUNET_PQ_result_spec_auto_from_type ("hash_code",
   1618                                             &td.details.policy_details.
   1619                                             hash_code),
   1620       GNUNET_PQ_result_spec_allow_null (
   1621         TALER_PQ_result_spec_json ("policy_json",
   1622                                    &td.details.policy_details.
   1623                                    policy_json),
   1624         &td.details.policy_details.no_policy_json),
   1625       GNUNET_PQ_result_spec_timestamp ("deadline",
   1626                                        &td.details.policy_details.
   1627                                        deadline),
   1628       TALER_PQ_RESULT_SPEC_AMOUNT ("commitment",
   1629                                    &td.details.policy_details.
   1630                                    commitment),
   1631       TALER_PQ_RESULT_SPEC_AMOUNT ("accumulated_total",
   1632                                    &td.details.policy_details.
   1633                                    accumulated_total),
   1634       TALER_PQ_RESULT_SPEC_AMOUNT ("fee",
   1635                                    &td.details.policy_details.
   1636                                    fee),
   1637       TALER_PQ_RESULT_SPEC_AMOUNT ("transferable",
   1638                                    &td.details.policy_details.
   1639                                    transferable),
   1640       GNUNET_PQ_result_spec_uint16 ("fulfillment_state",
   1641                                     &td.details.policy_details.
   1642                                     fulfillment_state),
   1643       GNUNET_PQ_result_spec_allow_null (
   1644         GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
   1645                                       &td.details.policy_details.
   1646                                       fulfillment_id),
   1647         &td.details.policy_details.no_fulfillment_id),
   1648       GNUNET_PQ_result_spec_end
   1649     };
   1650 
   1651     if (GNUNET_OK !=
   1652         GNUNET_PQ_extract_result (result,
   1653                                   rs,
   1654                                   i))
   1655     {
   1656       GNUNET_break (0);
   1657       ctx->error = true;
   1658       return;
   1659     }
   1660     ctx->cb (ctx->cb_cls,
   1661              &td);
   1662     GNUNET_PQ_cleanup_result (rs);
   1663   }
   1664 }
   1665 
   1666 
   1667 /**
   1668  * Function called with policy_fulfillments table entries.
   1669  *
   1670  * @param cls closure
   1671  * @param result the postgres result
   1672  * @param num_results the number of results in @a result
   1673  */
   1674 static void
   1675 lrbt_cb_table_policy_fulfillments (void *cls,
   1676                                    PGresult *result,
   1677                                    unsigned int num_results)
   1678 {
   1679   struct LookupRecordsByTableContext *ctx = cls;
   1680   struct TALER_EXCHANGEDB_TableData td = {
   1681     .table = TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS
   1682   };
   1683 
   1684   for (unsigned int i = 0; i<num_results; i++)
   1685   {
   1686     bool no_proof = false;
   1687     bool no_timestamp = false;
   1688     struct GNUNET_PQ_ResultSpec rs[] = {
   1689       GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
   1690                                     &td.serial),
   1691       GNUNET_PQ_result_spec_allow_null (
   1692         GNUNET_PQ_result_spec_timestamp ("fulfillment_timestamp",
   1693                                          &td.details.policy_fulfillments.
   1694                                          fulfillment_timestamp),
   1695         &no_timestamp),
   1696       GNUNET_PQ_result_spec_allow_null (
   1697         GNUNET_PQ_result_spec_string ("fulfillment_proof",
   1698                                       &td.details.policy_fulfillments.
   1699                                       fulfillment_proof),
   1700         &no_proof),
   1701       GNUNET_PQ_result_spec_end
   1702     };
   1703 
   1704     if (GNUNET_OK !=
   1705         GNUNET_PQ_extract_result (result,
   1706                                   rs,
   1707                                   i))
   1708     {
   1709       GNUNET_break (0);
   1710       ctx->error = true;
   1711       return;
   1712     }
   1713     ctx->cb (ctx->cb_cls,
   1714              &td);
   1715     GNUNET_PQ_cleanup_result (rs);
   1716   }
   1717 }
   1718 
   1719 
   1720 /**
   1721  * Function called with purse_requests table entries.
   1722  *
   1723  * @param cls closure
   1724  * @param result the postgres result
   1725  * @param num_results the number of results in @a result
   1726  */
   1727 static void
   1728 lrbt_cb_table_purse_requests (void *cls,
   1729                               PGresult *result,
   1730                               unsigned int num_results)
   1731 {
   1732   struct LookupRecordsByTableContext *ctx = cls;
   1733   struct PostgresClosure *pg = ctx->pg;
   1734   struct TALER_EXCHANGEDB_TableData td = {
   1735     .table = TALER_EXCHANGEDB_RT_PURSE_REQUESTS
   1736   };
   1737 
   1738   for (unsigned int i = 0; i<num_results; i++)
   1739   {
   1740     struct GNUNET_PQ_ResultSpec rs[] = {
   1741       GNUNET_PQ_result_spec_uint64 (
   1742         "purse_requests_serial_id",
   1743         &td.serial),
   1744       GNUNET_PQ_result_spec_auto_from_type (
   1745         "purse_pub",
   1746         &td.details.purse_requests.purse_pub),
   1747       GNUNET_PQ_result_spec_auto_from_type (
   1748         "merge_pub",
   1749         &td.details.purse_requests.merge_pub),
   1750       GNUNET_PQ_result_spec_timestamp (
   1751         "purse_creation",
   1752         &td.details.purse_requests.purse_creation),
   1753       GNUNET_PQ_result_spec_timestamp (
   1754         "purse_expiration",
   1755         &td.details.purse_requests.purse_expiration),
   1756       GNUNET_PQ_result_spec_auto_from_type (
   1757         "h_contract_terms",
   1758         &td.details.purse_requests.h_contract_terms),
   1759       GNUNET_PQ_result_spec_uint32 (
   1760         "age_limit",
   1761         &td.details.purse_requests.age_limit),
   1762       GNUNET_PQ_result_spec_uint32 (
   1763         "flags",
   1764         &td.details.purse_requests.flags),
   1765       TALER_PQ_RESULT_SPEC_AMOUNT (
   1766         "amount_with_fee",
   1767         &td.details.purse_requests.amount_with_fee),
   1768       TALER_PQ_RESULT_SPEC_AMOUNT (
   1769         "purse_fee",
   1770         &td.details.purse_requests.purse_fee),
   1771       GNUNET_PQ_result_spec_auto_from_type (
   1772         "purse_sig",
   1773         &td.details.purse_requests.purse_sig),
   1774       GNUNET_PQ_result_spec_end
   1775     };
   1776 
   1777     if (GNUNET_OK !=
   1778         GNUNET_PQ_extract_result (result,
   1779                                   rs,
   1780                                   i))
   1781     {
   1782       GNUNET_break (0);
   1783       ctx->error = true;
   1784       return;
   1785     }
   1786     ctx->cb (ctx->cb_cls,
   1787              &td);
   1788     GNUNET_PQ_cleanup_result (rs);
   1789   }
   1790 }
   1791 
   1792 
   1793 /**
   1794  * Function called with purse_decision table entries.
   1795  *
   1796  * @param cls closure
   1797  * @param result the postgres result
   1798  * @param num_results the number of results in @a result
   1799  */
   1800 static void
   1801 lrbt_cb_table_purse_decision (void *cls,
   1802                               PGresult *result,
   1803                               unsigned int num_results)
   1804 {
   1805   struct LookupRecordsByTableContext *ctx = cls;
   1806   struct TALER_EXCHANGEDB_TableData td = {
   1807     .table = TALER_EXCHANGEDB_RT_PURSE_DECISION
   1808   };
   1809 
   1810   for (unsigned int i = 0; i<num_results; i++)
   1811   {
   1812     struct GNUNET_PQ_ResultSpec rs[] = {
   1813       GNUNET_PQ_result_spec_uint64 (
   1814         "purse_refunds_serial_id",
   1815         &td.serial),
   1816       GNUNET_PQ_result_spec_auto_from_type (
   1817         "purse_pub",
   1818         &td.details.purse_decision.purse_pub),
   1819       GNUNET_PQ_result_spec_timestamp (
   1820         "action_timestamp",
   1821         &td.details.purse_decision.action_timestamp),
   1822       GNUNET_PQ_result_spec_bool (
   1823         "refunded",
   1824         &td.details.purse_decision.refunded),
   1825       GNUNET_PQ_result_spec_end
   1826     };
   1827 
   1828     if (GNUNET_OK !=
   1829         GNUNET_PQ_extract_result (result,
   1830                                   rs,
   1831                                   i))
   1832     {
   1833       GNUNET_break (0);
   1834       ctx->error = true;
   1835       return;
   1836     }
   1837     ctx->cb (ctx->cb_cls,
   1838              &td);
   1839     GNUNET_PQ_cleanup_result (rs);
   1840   }
   1841 }
   1842 
   1843 
   1844 /**
   1845  * Function called with purse_merges table entries.
   1846  *
   1847  * @param cls closure
   1848  * @param result the postgres result
   1849  * @param num_results the number of results in @a result
   1850  */
   1851 static void
   1852 lrbt_cb_table_purse_merges (void *cls,
   1853                             PGresult *result,
   1854                             unsigned int num_results)
   1855 {
   1856   struct LookupRecordsByTableContext *ctx = cls;
   1857   struct TALER_EXCHANGEDB_TableData td = {
   1858     .table = TALER_EXCHANGEDB_RT_PURSE_MERGES
   1859   };
   1860 
   1861   for (unsigned int i = 0; i<num_results; i++)
   1862   {
   1863     struct GNUNET_PQ_ResultSpec rs[] = {
   1864       GNUNET_PQ_result_spec_uint64 (
   1865         "purse_merge_request_serial_id",
   1866         &td.serial),
   1867       GNUNET_PQ_result_spec_uint64 (
   1868         "partner_serial_id",
   1869         &td.details.purse_merges.partner_serial_id),
   1870       GNUNET_PQ_result_spec_auto_from_type (
   1871         "reserve_pub",
   1872         &td.details.purse_merges.reserve_pub),
   1873       GNUNET_PQ_result_spec_auto_from_type (
   1874         "purse_pub",
   1875         &td.details.purse_merges.purse_pub),
   1876       GNUNET_PQ_result_spec_auto_from_type (
   1877         "merge_sig",
   1878         &td.details.purse_merges.merge_sig),
   1879       GNUNET_PQ_result_spec_timestamp (
   1880         "merge_timestamp",
   1881         &td.details.purse_merges.merge_timestamp),
   1882       GNUNET_PQ_result_spec_end
   1883     };
   1884 
   1885     if (GNUNET_OK !=
   1886         GNUNET_PQ_extract_result (result,
   1887                                   rs,
   1888                                   i))
   1889     {
   1890       GNUNET_break (0);
   1891       ctx->error = true;
   1892       return;
   1893     }
   1894     ctx->cb (ctx->cb_cls,
   1895              &td);
   1896     GNUNET_PQ_cleanup_result (rs);
   1897   }
   1898 }
   1899 
   1900 
   1901 /**
   1902  * Function called with purse_deposits table entries.
   1903  *
   1904  * @param cls closure
   1905  * @param result the postgres result
   1906  * @param num_results the number of results in @a result
   1907  */
   1908 static void
   1909 lrbt_cb_table_purse_deposits (void *cls,
   1910                               PGresult *result,
   1911                               unsigned int num_results)
   1912 {
   1913   struct LookupRecordsByTableContext *ctx = cls;
   1914   struct PostgresClosure *pg = ctx->pg;
   1915   struct TALER_EXCHANGEDB_TableData td = {
   1916     .table = TALER_EXCHANGEDB_RT_PURSE_DEPOSITS
   1917   };
   1918 
   1919   for (unsigned int i = 0; i<num_results; i++)
   1920   {
   1921     struct GNUNET_PQ_ResultSpec rs[] = {
   1922       GNUNET_PQ_result_spec_uint64 (
   1923         "purse_deposit_serial_id",
   1924         &td.serial),
   1925       GNUNET_PQ_result_spec_uint64 (
   1926         "partner_serial_id",
   1927         &td.details.purse_deposits.partner_serial_id),
   1928       GNUNET_PQ_result_spec_auto_from_type (
   1929         "purse_pub",
   1930         &td.details.purse_deposits.purse_pub),
   1931       GNUNET_PQ_result_spec_auto_from_type (
   1932         "coin_pub",
   1933         &td.details.purse_deposits.coin_pub),
   1934       TALER_PQ_RESULT_SPEC_AMOUNT (
   1935         "amount_with_fee",
   1936         &td.details.purse_deposits.amount_with_fee),
   1937       GNUNET_PQ_result_spec_auto_from_type (
   1938         "coin_sig",
   1939         &td.details.purse_deposits.coin_sig),
   1940       GNUNET_PQ_result_spec_end
   1941     };
   1942 
   1943     if (GNUNET_OK !=
   1944         GNUNET_PQ_extract_result (result,
   1945                                   rs,
   1946                                   i))
   1947     {
   1948       GNUNET_break (0);
   1949       ctx->error = true;
   1950       return;
   1951     }
   1952     ctx->cb (ctx->cb_cls,
   1953              &td);
   1954     GNUNET_PQ_cleanup_result (rs);
   1955   }
   1956 }
   1957 
   1958 
   1959 /**
   1960  * Function called with account_merges table entries.
   1961  *
   1962  * @param cls closure
   1963  * @param result the postgres result
   1964  * @param num_results the number of results in @a result
   1965  */
   1966 static void
   1967 lrbt_cb_table_account_merges (void *cls,
   1968                               PGresult *result,
   1969                               unsigned int num_results)
   1970 {
   1971   struct LookupRecordsByTableContext *ctx = cls;
   1972   struct TALER_EXCHANGEDB_TableData td = {
   1973     .table = TALER_EXCHANGEDB_RT_ACCOUNT_MERGES
   1974   };
   1975 
   1976   for (unsigned int i = 0; i<num_results; i++)
   1977   {
   1978     struct GNUNET_PQ_ResultSpec rs[] = {
   1979       GNUNET_PQ_result_spec_uint64 (
   1980         "account_merge_request_serial_id",
   1981         &td.serial),
   1982       GNUNET_PQ_result_spec_auto_from_type (
   1983         "reserve_pub",
   1984         &td.details.account_merges.reserve_pub),
   1985       GNUNET_PQ_result_spec_auto_from_type (
   1986         "reserve_sig",
   1987         &td.details.account_merges.reserve_sig),
   1988       GNUNET_PQ_result_spec_auto_from_type (
   1989         "purse_pub",
   1990         &td.details.account_merges.purse_pub),
   1991       GNUNET_PQ_result_spec_auto_from_type (
   1992         "wallet_h_payto",
   1993         &td.details.account_merges.wallet_h_payto),
   1994       GNUNET_PQ_result_spec_end
   1995     };
   1996 
   1997     if (GNUNET_OK !=
   1998         GNUNET_PQ_extract_result (result,
   1999                                   rs,
   2000                                   i))
   2001     {
   2002       GNUNET_break (0);
   2003       ctx->error = true;
   2004       return;
   2005     }
   2006     ctx->cb (ctx->cb_cls,
   2007              &td);
   2008     GNUNET_PQ_cleanup_result (rs);
   2009   }
   2010 }
   2011 
   2012 
   2013 /**
   2014  * Function called with history_requests table entries.
   2015  *
   2016  * @param cls closure
   2017  * @param result the postgres result
   2018  * @param num_results the number of results in @a result
   2019  */
   2020 static void
   2021 lrbt_cb_table_history_requests (void *cls,
   2022                                 PGresult *result,
   2023                                 unsigned int num_results)
   2024 {
   2025   struct LookupRecordsByTableContext *ctx = cls;
   2026   struct PostgresClosure *pg = ctx->pg;
   2027   struct TALER_EXCHANGEDB_TableData td = {
   2028     .table = TALER_EXCHANGEDB_RT_HISTORY_REQUESTS
   2029   };
   2030 
   2031   for (unsigned int i = 0; i<num_results; i++)
   2032   {
   2033     struct GNUNET_PQ_ResultSpec rs[] = {
   2034       GNUNET_PQ_result_spec_uint64 (
   2035         "history_request_serial_id",
   2036         &td.serial),
   2037       GNUNET_PQ_result_spec_auto_from_type (
   2038         "reserve_pub",
   2039         &td.details.history_requests.reserve_pub),
   2040       GNUNET_PQ_result_spec_auto_from_type (
   2041         "reserve_sig",
   2042         &td.details.history_requests.reserve_sig),
   2043       TALER_PQ_RESULT_SPEC_AMOUNT (
   2044         "history_fee",
   2045         &td.details.history_requests.history_fee),
   2046       GNUNET_PQ_result_spec_end
   2047     };
   2048 
   2049     if (GNUNET_OK !=
   2050         GNUNET_PQ_extract_result (result,
   2051                                   rs,
   2052                                   i))
   2053     {
   2054       GNUNET_break (0);
   2055       ctx->error = true;
   2056       return;
   2057     }
   2058     ctx->cb (ctx->cb_cls,
   2059              &td);
   2060     GNUNET_PQ_cleanup_result (rs);
   2061   }
   2062 }
   2063 
   2064 
   2065 /**
   2066  * Function called with close_requests table entries.
   2067  *
   2068  * @param cls closure
   2069  * @param result the postgres result
   2070  * @param num_results the number of results in @a result
   2071  */
   2072 static void
   2073 lrbt_cb_table_close_requests (void *cls,
   2074                               PGresult *result,
   2075                               unsigned int num_results)
   2076 {
   2077   struct LookupRecordsByTableContext *ctx = cls;
   2078   struct PostgresClosure *pg = ctx->pg;
   2079   struct TALER_EXCHANGEDB_TableData td = {
   2080     .table = TALER_EXCHANGEDB_RT_CLOSE_REQUESTS
   2081   };
   2082 
   2083   for (unsigned int i = 0; i<num_results; i++)
   2084   {
   2085     struct GNUNET_PQ_ResultSpec rs[] = {
   2086       GNUNET_PQ_result_spec_uint64 (
   2087         "close_request_serial_id",
   2088         &td.serial),
   2089       GNUNET_PQ_result_spec_auto_from_type (
   2090         "reserve_pub",
   2091         &td.details.close_requests.reserve_pub),
   2092       GNUNET_PQ_result_spec_timestamp (
   2093         "close_timestamp",
   2094         &td.details.close_requests.close_timestamp),
   2095       GNUNET_PQ_result_spec_auto_from_type (
   2096         "reserve_sig",
   2097         &td.details.close_requests.reserve_sig),
   2098       TALER_PQ_RESULT_SPEC_AMOUNT (
   2099         "close",
   2100         &td.details.close_requests.close),
   2101       TALER_PQ_RESULT_SPEC_AMOUNT (
   2102         "close_fee",
   2103         &td.details.close_requests.close_fee),
   2104       GNUNET_PQ_result_spec_string (
   2105         "payto_uri",
   2106         &td.details.close_requests.payto_uri.full_payto),
   2107       GNUNET_PQ_result_spec_end
   2108     };
   2109 
   2110     if (GNUNET_OK !=
   2111         GNUNET_PQ_extract_result (result,
   2112                                   rs,
   2113                                   i))
   2114     {
   2115       GNUNET_break (0);
   2116       ctx->error = true;
   2117       return;
   2118     }
   2119     ctx->cb (ctx->cb_cls,
   2120              &td);
   2121     GNUNET_PQ_cleanup_result (rs);
   2122   }
   2123 }
   2124 
   2125 
   2126 /**
   2127  * Function called with wads_out table entries.
   2128  *
   2129  * @param cls closure
   2130  * @param result the postgres result
   2131  * @param num_results the number of results in @a result
   2132  */
   2133 static void
   2134 lrbt_cb_table_wads_out (void *cls,
   2135                         PGresult *result,
   2136                         unsigned int num_results)
   2137 {
   2138   struct LookupRecordsByTableContext *ctx = cls;
   2139   struct PostgresClosure *pg = ctx->pg;
   2140   struct TALER_EXCHANGEDB_TableData td = {
   2141     .table = TALER_EXCHANGEDB_RT_WADS_OUT
   2142   };
   2143 
   2144   for (unsigned int i = 0; i<num_results; i++)
   2145   {
   2146     struct GNUNET_PQ_ResultSpec rs[] = {
   2147       GNUNET_PQ_result_spec_uint64 (
   2148         "wad_out_serial_id",
   2149         &td.serial),
   2150       GNUNET_PQ_result_spec_auto_from_type (
   2151         "wad_id",
   2152         &td.details.wads_out.wad_id),
   2153       GNUNET_PQ_result_spec_uint64 (
   2154         "partner_serial_id",
   2155         &td.details.wads_out.partner_serial_id),
   2156       TALER_PQ_RESULT_SPEC_AMOUNT (
   2157         "amount",
   2158         &td.details.wads_out.amount),
   2159       GNUNET_PQ_result_spec_timestamp (
   2160         "execution_time",
   2161         &td.details.wads_out.execution_time),
   2162       GNUNET_PQ_result_spec_end
   2163     };
   2164 
   2165     if (GNUNET_OK !=
   2166         GNUNET_PQ_extract_result (result,
   2167                                   rs,
   2168                                   i))
   2169     {
   2170       GNUNET_break (0);
   2171       ctx->error = true;
   2172       return;
   2173     }
   2174     ctx->cb (ctx->cb_cls,
   2175              &td);
   2176     GNUNET_PQ_cleanup_result (rs);
   2177   }
   2178 }
   2179 
   2180 
   2181 /**
   2182  * Function called with wads_out_entries table entries.
   2183  *
   2184  * @param cls closure
   2185  * @param result the postgres result
   2186  * @param num_results the number of results in @a result
   2187  */
   2188 static void
   2189 lrbt_cb_table_wads_out_entries (void *cls,
   2190                                 PGresult *result,
   2191                                 unsigned int num_results)
   2192 {
   2193   struct LookupRecordsByTableContext *ctx = cls;
   2194   struct PostgresClosure *pg = ctx->pg;
   2195   struct TALER_EXCHANGEDB_TableData td = {
   2196     .table = TALER_EXCHANGEDB_RT_WADS_OUT_ENTRIES
   2197   };
   2198 
   2199   for (unsigned int i = 0; i<num_results; i++)
   2200   {
   2201     struct GNUNET_PQ_ResultSpec rs[] = {
   2202       GNUNET_PQ_result_spec_uint64 (
   2203         "wad_out_entry_serial_id",
   2204         &td.serial),
   2205       GNUNET_PQ_result_spec_auto_from_type (
   2206         "reserve_pub",
   2207         &td.details.wads_out_entries.reserve_pub),
   2208       GNUNET_PQ_result_spec_auto_from_type (
   2209         "purse_pub",
   2210         &td.details.wads_out_entries.purse_pub),
   2211       GNUNET_PQ_result_spec_auto_from_type (
   2212         "h_contract",
   2213         &td.details.wads_out_entries.h_contract),
   2214       GNUNET_PQ_result_spec_timestamp (
   2215         "purse_expiration",
   2216         &td.details.wads_out_entries.purse_expiration),
   2217       GNUNET_PQ_result_spec_timestamp (
   2218         "merge_timestamp",
   2219         &td.details.wads_out_entries.merge_timestamp),
   2220       TALER_PQ_RESULT_SPEC_AMOUNT (
   2221         "amount_with_fee",
   2222         &td.details.wads_out_entries.amount_with_fee),
   2223       TALER_PQ_RESULT_SPEC_AMOUNT (
   2224         "wad_fee",
   2225         &td.details.wads_out_entries.wad_fee),
   2226       TALER_PQ_RESULT_SPEC_AMOUNT (
   2227         "deposit_fees",
   2228         &td.details.wads_out_entries.deposit_fees),
   2229       GNUNET_PQ_result_spec_auto_from_type (
   2230         "reserve_sig",
   2231         &td.details.wads_out_entries.reserve_sig),
   2232       GNUNET_PQ_result_spec_auto_from_type (
   2233         "purse_sig",
   2234         &td.details.wads_out_entries.purse_sig),
   2235       GNUNET_PQ_result_spec_end
   2236     };
   2237 
   2238     if (GNUNET_OK !=
   2239         GNUNET_PQ_extract_result (result,
   2240                                   rs,
   2241                                   i))
   2242     {
   2243       GNUNET_break (0);
   2244       ctx->error = true;
   2245       return;
   2246     }
   2247     ctx->cb (ctx->cb_cls,
   2248              &td);
   2249     GNUNET_PQ_cleanup_result (rs);
   2250   }
   2251 }
   2252 
   2253 
   2254 /**
   2255  * Function called with wads_in table entries.
   2256  *
   2257  * @param cls closure
   2258  * @param result the postgres result
   2259  * @param num_results the number of results in @a result
   2260  */
   2261 static void
   2262 lrbt_cb_table_wads_in (void *cls,
   2263                        PGresult *result,
   2264                        unsigned int num_results)
   2265 {
   2266   struct LookupRecordsByTableContext *ctx = cls;
   2267   struct PostgresClosure *pg = ctx->pg;
   2268   struct TALER_EXCHANGEDB_TableData td = {
   2269     .table = TALER_EXCHANGEDB_RT_WADS_IN
   2270   };
   2271 
   2272   for (unsigned int i = 0; i<num_results; i++)
   2273   {
   2274     struct GNUNET_PQ_ResultSpec rs[] = {
   2275       GNUNET_PQ_result_spec_uint64 (
   2276         "wad_in_serial_id",
   2277         &td.serial),
   2278       GNUNET_PQ_result_spec_auto_from_type (
   2279         "wad_id",
   2280         &td.details.wads_in.wad_id),
   2281       GNUNET_PQ_result_spec_string (
   2282         "origin_exchange_url",
   2283         &td.details.wads_in.origin_exchange_url),
   2284       TALER_PQ_RESULT_SPEC_AMOUNT (
   2285         "amount",
   2286         &td.details.wads_in.amount),
   2287       GNUNET_PQ_result_spec_timestamp (
   2288         "arrival_time",
   2289         &td.details.wads_in.arrival_time),
   2290       GNUNET_PQ_result_spec_end
   2291     };
   2292 
   2293     if (GNUNET_OK !=
   2294         GNUNET_PQ_extract_result (result,
   2295                                   rs,
   2296                                   i))
   2297     {
   2298       GNUNET_break (0);
   2299       ctx->error = true;
   2300       return;
   2301     }
   2302     ctx->cb (ctx->cb_cls,
   2303              &td);
   2304     GNUNET_PQ_cleanup_result (rs);
   2305   }
   2306 }
   2307 
   2308 
   2309 /**
   2310  * Function called with wads_in_entries table entries.
   2311  *
   2312  * @param cls closure
   2313  * @param result the postgres result
   2314  * @param num_results the number of results in @a result
   2315  */
   2316 static void
   2317 lrbt_cb_table_wads_in_entries (void *cls,
   2318                                PGresult *result,
   2319                                unsigned int num_results)
   2320 {
   2321   struct LookupRecordsByTableContext *ctx = cls;
   2322   struct PostgresClosure *pg = ctx->pg;
   2323   struct TALER_EXCHANGEDB_TableData td = {
   2324     .table = TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES
   2325   };
   2326 
   2327   for (unsigned int i = 0; i<num_results; i++)
   2328   {
   2329     struct GNUNET_PQ_ResultSpec rs[] = {
   2330       GNUNET_PQ_result_spec_uint64 (
   2331         "wad_in_entry_serial_id",
   2332         &td.serial),
   2333       GNUNET_PQ_result_spec_auto_from_type (
   2334         "reserve_pub",
   2335         &td.details.wads_in_entries.reserve_pub),
   2336       GNUNET_PQ_result_spec_auto_from_type (
   2337         "purse_pub",
   2338         &td.details.wads_in_entries.purse_pub),
   2339       GNUNET_PQ_result_spec_auto_from_type (
   2340         "h_contract",
   2341         &td.details.wads_in_entries.h_contract),
   2342       GNUNET_PQ_result_spec_timestamp (
   2343         "purse_expiration",
   2344         &td.details.wads_in_entries.purse_expiration),
   2345       GNUNET_PQ_result_spec_timestamp (
   2346         "merge_timestamp",
   2347         &td.details.wads_in_entries.merge_timestamp),
   2348       TALER_PQ_RESULT_SPEC_AMOUNT (
   2349         "amount_with_fee",
   2350         &td.details.wads_in_entries.amount_with_fee),
   2351       TALER_PQ_RESULT_SPEC_AMOUNT (
   2352         "wad_fee",
   2353         &td.details.wads_in_entries.wad_fee),
   2354       TALER_PQ_RESULT_SPEC_AMOUNT (
   2355         "deposit_fees",
   2356         &td.details.wads_in_entries.deposit_fees),
   2357       GNUNET_PQ_result_spec_auto_from_type (
   2358         "reserve_sig",
   2359         &td.details.wads_in_entries.reserve_sig),
   2360       GNUNET_PQ_result_spec_auto_from_type (
   2361         "purse_sig",
   2362         &td.details.wads_in_entries.purse_sig),
   2363       GNUNET_PQ_result_spec_end
   2364     };
   2365 
   2366     if (GNUNET_OK !=
   2367         GNUNET_PQ_extract_result (result,
   2368                                   rs,
   2369                                   i))
   2370     {
   2371       GNUNET_break (0);
   2372       ctx->error = true;
   2373       return;
   2374     }
   2375     ctx->cb (ctx->cb_cls,
   2376              &td);
   2377     GNUNET_PQ_cleanup_result (rs);
   2378   }
   2379 }
   2380 
   2381 
   2382 /**
   2383  * Function called with profit_drains table entries.
   2384  *
   2385  * @param cls closure
   2386  * @param result the postgres result
   2387  * @param num_results the number of results in @a result
   2388  */
   2389 static void
   2390 lrbt_cb_table_profit_drains (void *cls,
   2391                              PGresult *result,
   2392                              unsigned int num_results)
   2393 {
   2394   struct LookupRecordsByTableContext *ctx = cls;
   2395   struct PostgresClosure *pg = ctx->pg;
   2396   struct TALER_EXCHANGEDB_TableData td = {
   2397     .table = TALER_EXCHANGEDB_RT_PROFIT_DRAINS
   2398   };
   2399 
   2400   for (unsigned int i = 0; i<num_results; i++)
   2401   {
   2402     struct GNUNET_PQ_ResultSpec rs[] = {
   2403       GNUNET_PQ_result_spec_uint64 (
   2404         "profit_drain_serial_id",
   2405         &td.serial),
   2406       GNUNET_PQ_result_spec_auto_from_type (
   2407         "wtid",
   2408         &td.details.profit_drains.wtid),
   2409       GNUNET_PQ_result_spec_string (
   2410         "account_section",
   2411         &td.details.profit_drains.account_section),
   2412       GNUNET_PQ_result_spec_string (
   2413         "payto_uri",
   2414         &td.details.profit_drains.payto_uri.full_payto),
   2415       GNUNET_PQ_result_spec_timestamp (
   2416         "trigger_date",
   2417         &td.details.profit_drains.trigger_date),
   2418       TALER_PQ_RESULT_SPEC_AMOUNT (
   2419         "amount",
   2420         &td.details.profit_drains.amount),
   2421       GNUNET_PQ_result_spec_auto_from_type (
   2422         "master_sig",
   2423         &td.details.profit_drains.master_sig),
   2424       GNUNET_PQ_result_spec_end
   2425     };
   2426 
   2427     if (GNUNET_OK !=
   2428         GNUNET_PQ_extract_result (result,
   2429                                   rs,
   2430                                   i))
   2431     {
   2432       GNUNET_break (0);
   2433       ctx->error = true;
   2434       return;
   2435     }
   2436     ctx->cb (ctx->cb_cls,
   2437              &td);
   2438     GNUNET_PQ_cleanup_result (rs);
   2439   }
   2440 }
   2441 
   2442 
   2443 /**
   2444  * Function called with aml_staff table entries.
   2445  *
   2446  * @param cls closure
   2447  * @param result the postgres result
   2448  * @param num_results the number of results in @a result
   2449  */
   2450 static void
   2451 lrbt_cb_table_aml_staff (void *cls,
   2452                          PGresult *result,
   2453                          unsigned int num_results)
   2454 {
   2455   struct LookupRecordsByTableContext *ctx = cls;
   2456   struct TALER_EXCHANGEDB_TableData td = {
   2457     .table = TALER_EXCHANGEDB_RT_AML_STAFF
   2458   };
   2459 
   2460   for (unsigned int i = 0; i<num_results; i++)
   2461   {
   2462     struct GNUNET_PQ_ResultSpec rs[] = {
   2463       GNUNET_PQ_result_spec_uint64 (
   2464         "aml_staff_uuid",
   2465         &td.serial),
   2466       GNUNET_PQ_result_spec_auto_from_type (
   2467         "decider_pub",
   2468         &td.details.aml_staff.decider_pub),
   2469       GNUNET_PQ_result_spec_auto_from_type (
   2470         "master_sig",
   2471         &td.details.aml_staff.master_sig),
   2472       GNUNET_PQ_result_spec_string (
   2473         "decider_name",
   2474         &td.details.aml_staff.decider_name),
   2475       GNUNET_PQ_result_spec_bool (
   2476         "is_active",
   2477         &td.details.aml_staff.is_active),
   2478       GNUNET_PQ_result_spec_bool (
   2479         "read_only",
   2480         &td.details.aml_staff.read_only),
   2481       GNUNET_PQ_result_spec_timestamp (
   2482         "last_change",
   2483         &td.details.aml_staff.last_change),
   2484       GNUNET_PQ_result_spec_end
   2485     };
   2486 
   2487     if (GNUNET_OK !=
   2488         GNUNET_PQ_extract_result (result,
   2489                                   rs,
   2490                                   i))
   2491     {
   2492       GNUNET_break (0);
   2493       ctx->error = true;
   2494       return;
   2495     }
   2496     ctx->cb (ctx->cb_cls,
   2497              &td);
   2498     GNUNET_PQ_cleanup_result (rs);
   2499   }
   2500 }
   2501 
   2502 
   2503 /**
   2504  * Function called with purse_deletion table entries.
   2505  *
   2506  * @param cls closure
   2507  * @param result the postgres result
   2508  * @param num_results the number of results in @a result
   2509  */
   2510 static void
   2511 lrbt_cb_table_purse_deletion (void *cls,
   2512                               PGresult *result,
   2513                               unsigned int num_results)
   2514 {
   2515   struct LookupRecordsByTableContext *ctx = cls;
   2516   struct TALER_EXCHANGEDB_TableData td = {
   2517     .table = TALER_EXCHANGEDB_RT_PURSE_DELETION
   2518   };
   2519 
   2520   for (unsigned int i = 0; i<num_results; i++)
   2521   {
   2522     struct GNUNET_PQ_ResultSpec rs[] = {
   2523       GNUNET_PQ_result_spec_uint64 (
   2524         "purse_deletion_serial_id",
   2525         &td.serial),
   2526       GNUNET_PQ_result_spec_auto_from_type (
   2527         "purse_sig",
   2528         &td.details.purse_deletion.purse_sig),
   2529       GNUNET_PQ_result_spec_auto_from_type (
   2530         "purse_pub",
   2531         &td.details.purse_deletion.purse_pub),
   2532       GNUNET_PQ_result_spec_end
   2533     };
   2534 
   2535     if (GNUNET_OK !=
   2536         GNUNET_PQ_extract_result (result,
   2537                                   rs,
   2538                                   i))
   2539     {
   2540       GNUNET_break (0);
   2541       ctx->error = true;
   2542       return;
   2543     }
   2544     ctx->cb (ctx->cb_cls,
   2545              &td);
   2546     GNUNET_PQ_cleanup_result (rs);
   2547   }
   2548 }
   2549 
   2550 
   2551 /**
   2552  * Function called with withdraw table entries.
   2553  *
   2554  * @param cls closure
   2555  * @param result the postgres result
   2556  * @param num_results the number of results in @a result
   2557  */
   2558 static void
   2559 lrbt_cb_table_withdraw (void *cls,
   2560                         PGresult *result,
   2561                         unsigned int num_results)
   2562 {
   2563   struct LookupRecordsByTableContext *ctx = cls;
   2564   struct PostgresClosure *pg = ctx->pg;
   2565   struct TALER_EXCHANGEDB_TableData td = {
   2566     .table = TALER_EXCHANGEDB_RT_WITHDRAW
   2567   };
   2568 
   2569   for (unsigned int i = 0; i<num_results; i++)
   2570   {
   2571     bool no_max_age;
   2572     bool no_noreveal_index;
   2573     bool no_selected_h;
   2574     bool no_cs_r_values;
   2575     bool no_cs_r_choices;
   2576     size_t num_sigs;
   2577     struct GNUNET_PQ_ResultSpec rs[] = {
   2578       GNUNET_PQ_result_spec_uint64 (
   2579         "withdraw_id",
   2580         &td.serial),
   2581       GNUNET_PQ_result_spec_auto_from_type (
   2582         "planchets_h",
   2583         &td.details.withdraw.planchets_h),
   2584       GNUNET_PQ_result_spec_timestamp (
   2585         "execution_date",
   2586         &td.details.withdraw.execution_date),
   2587       TALER_PQ_RESULT_SPEC_AMOUNT (
   2588         "amount_with_fee",
   2589         &td.details.withdraw.amount_with_fee),
   2590       GNUNET_PQ_result_spec_auto_from_type (
   2591         "reserve_pub",
   2592         &td.details.withdraw.reserve_pub),
   2593       GNUNET_PQ_result_spec_auto_from_type (
   2594         "reserve_sig",
   2595         &td.details.withdraw.reserve_sig),
   2596       GNUNET_PQ_result_spec_allow_null (
   2597         GNUNET_PQ_result_spec_uint16 (
   2598           "max_age",
   2599           &td.details.withdraw.max_age),
   2600         &no_max_age),
   2601       GNUNET_PQ_result_spec_allow_null (
   2602         GNUNET_PQ_result_spec_uint16 (
   2603           "noreveal_index",
   2604           &td.details.withdraw.noreveal_index),
   2605         &no_noreveal_index),
   2606       GNUNET_PQ_result_spec_allow_null (
   2607         GNUNET_PQ_result_spec_auto_from_type (
   2608           "selected_h",
   2609           &td.details.withdraw.selected_h),
   2610         &no_selected_h),
   2611       GNUNET_PQ_result_spec_allow_null (
   2612         GNUNET_PQ_result_spec_auto_from_type (
   2613           "blinding_seed",
   2614           &td.details.withdraw.blinding_seed),
   2615         &td.details.withdraw.no_blinding_seed),
   2616       GNUNET_PQ_result_spec_allow_null (
   2617         TALER_PQ_result_spec_array_cs_r_pub (
   2618           pg->conn,
   2619           "cs_r_values",
   2620           &td.details.withdraw.num_cs_r_values,
   2621           &td.details.withdraw.cs_r_values),
   2622         &no_cs_r_values),
   2623       GNUNET_PQ_result_spec_allow_null (
   2624         GNUNET_PQ_result_spec_uint64 (
   2625           "cs_r_choices",
   2626           &td.details.withdraw.cs_r_choices),
   2627         &no_cs_r_choices),
   2628       GNUNET_PQ_result_spec_array_uint64 (
   2629         pg->conn,
   2630         "denom_serials",
   2631         &td.details.withdraw.num_coins,
   2632         &td.details.withdraw.denom_serials),
   2633       TALER_PQ_result_spec_array_blinded_denom_sig (
   2634         pg->conn,
   2635         "denom_sigs",
   2636         &num_sigs,
   2637         &td.details.withdraw.denom_sigs),
   2638       GNUNET_PQ_result_spec_end
   2639     };
   2640 
   2641     if (GNUNET_OK !=
   2642         GNUNET_PQ_extract_result (result,
   2643                                   rs,
   2644                                   i))
   2645     {
   2646       GNUNET_break (0);
   2647       ctx->error = true;
   2648       GNUNET_PQ_cleanup_result (rs);
   2649       return;
   2650     }
   2651     if (num_sigs != td.details.withdraw.num_coins)
   2652     {
   2653       GNUNET_break (0);
   2654       ctx->error = true;
   2655       GNUNET_PQ_cleanup_result (rs);
   2656       return;
   2657     }
   2658     if (no_max_age != no_noreveal_index)
   2659     {
   2660       GNUNET_break (0);
   2661       ctx->error = true;
   2662       GNUNET_PQ_cleanup_result (rs);
   2663       return;
   2664     }
   2665     if (no_max_age != no_selected_h)
   2666     {
   2667       GNUNET_break (0);
   2668       ctx->error = true;
   2669       GNUNET_PQ_cleanup_result (rs);
   2670       return;
   2671     }
   2672     if (no_cs_r_values != no_cs_r_choices)
   2673     {
   2674       GNUNET_break (0);
   2675       ctx->error = true;
   2676       GNUNET_PQ_cleanup_result (rs);
   2677       return;
   2678     }
   2679     if (no_cs_r_values != td.details.withdraw.no_blinding_seed)
   2680     {
   2681       GNUNET_break (0);
   2682       ctx->error = true;
   2683       GNUNET_PQ_cleanup_result (rs);
   2684       return;
   2685     }
   2686     td.details.withdraw.age_proof_required = ! no_max_age;
   2687     ctx->cb (ctx->cb_cls,
   2688              &td);
   2689     GNUNET_PQ_cleanup_result (rs);
   2690   }
   2691 }
   2692 
   2693 
   2694 /**
   2695  * Function called with legitimization_measures table entries.
   2696  *
   2697  * @param cls closure
   2698  * @param result the postgres result
   2699  * @param num_results the number of results in @a result
   2700  */
   2701 static void
   2702 lrbt_cb_table_legitimization_measures (void *cls,
   2703                                        PGresult *result,
   2704                                        unsigned int num_results)
   2705 {
   2706   struct LookupRecordsByTableContext *ctx = cls;
   2707   struct TALER_EXCHANGEDB_TableData td = {
   2708     .table = TALER_EXCHANGEDB_RT_LEGITIMIZATION_MEASURES
   2709   };
   2710 
   2711   for (unsigned int i = 0; i<num_results; i++)
   2712   {
   2713     struct GNUNET_PQ_ResultSpec rs[] = {
   2714       GNUNET_PQ_result_spec_uint64 ("serial",
   2715                                     &td.serial),
   2716       GNUNET_PQ_result_spec_auto_from_type (
   2717         "access_token",
   2718         &td.details.legitimization_measures.target_token),
   2719       GNUNET_PQ_result_spec_timestamp (
   2720         "start_time",
   2721         &td.details.legitimization_measures.start_time),
   2722       TALER_PQ_result_spec_json (
   2723         "jmeasures",
   2724         &td.details.legitimization_measures.measures),
   2725       GNUNET_PQ_result_spec_uint32 (
   2726         "display_priority",
   2727         &td.details.legitimization_measures.display_priority),
   2728       GNUNET_PQ_result_spec_end
   2729     };
   2730 
   2731     if (GNUNET_OK !=
   2732         GNUNET_PQ_extract_result (result,
   2733                                   rs,
   2734                                   i))
   2735     {
   2736       GNUNET_break (0);
   2737       ctx->error = true;
   2738       return;
   2739     }
   2740     ctx->cb (ctx->cb_cls,
   2741              &td);
   2742     GNUNET_PQ_cleanup_result (rs);
   2743   }
   2744 }
   2745 
   2746 
   2747 /**
   2748  * Function called with legitimization_outcomes table entries.
   2749  *
   2750  * @param cls closure
   2751  * @param result the postgres result
   2752  * @param num_results the number of results in @a result
   2753  */
   2754 static void
   2755 lrbt_cb_table_legitimization_outcomes (void *cls,
   2756                                        PGresult *result,
   2757                                        unsigned int num_results)
   2758 {
   2759   struct LookupRecordsByTableContext *ctx = cls;
   2760   struct TALER_EXCHANGEDB_TableData td = {
   2761     .table = TALER_EXCHANGEDB_RT_LEGITIMIZATION_OUTCOMES
   2762   };
   2763 
   2764   for (unsigned int i = 0; i<num_results; i++)
   2765   {
   2766     struct GNUNET_PQ_ResultSpec rs[] = {
   2767       GNUNET_PQ_result_spec_uint64 ("serial",
   2768                                     &td.serial),
   2769       GNUNET_PQ_result_spec_auto_from_type (
   2770         "h_payto",
   2771         &td.details.legitimization_outcomes.h_payto),
   2772       GNUNET_PQ_result_spec_timestamp (
   2773         "decision_time",
   2774         &td.details.legitimization_outcomes.decision_time),
   2775       GNUNET_PQ_result_spec_timestamp (
   2776         "expiration_time",
   2777         &td.details.legitimization_outcomes.expiration_time),
   2778       GNUNET_PQ_result_spec_allow_null (
   2779         TALER_PQ_result_spec_json (
   2780           "jproperties",
   2781           &td.details.legitimization_outcomes.properties),
   2782         NULL),
   2783       GNUNET_PQ_result_spec_bool (
   2784         "to_investigate_id",
   2785         &td.details.legitimization_outcomes.to_investigate),
   2786       TALER_PQ_result_spec_json (
   2787         "jnew_rules",
   2788         &td.details.legitimization_outcomes.new_rules),
   2789       GNUNET_PQ_result_spec_end
   2790     };
   2791 
   2792     if (GNUNET_OK !=
   2793         GNUNET_PQ_extract_result (result,
   2794                                   rs,
   2795                                   i))
   2796     {
   2797       GNUNET_break (0);
   2798       ctx->error = true;
   2799       return;
   2800     }
   2801     ctx->cb (ctx->cb_cls,
   2802              &td);
   2803     GNUNET_PQ_cleanup_result (rs);
   2804   }
   2805 }
   2806 
   2807 
   2808 /**
   2809  * Function called with legitimization_processes table entries.
   2810  *
   2811  * @param cls closure
   2812  * @param result the postgres result
   2813  * @param num_results the number of results in @a result
   2814  */
   2815 static void
   2816 lrbt_cb_table_legitimization_processes (void *cls,
   2817                                         PGresult *result,
   2818                                         unsigned int num_results)
   2819 {
   2820   struct LookupRecordsByTableContext *ctx = cls;
   2821   struct TALER_EXCHANGEDB_TableData td = {
   2822     .table = TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES
   2823   };
   2824 
   2825   for (unsigned int i = 0; i<num_results; i++)
   2826   {
   2827     struct GNUNET_PQ_ResultSpec rs[] = {
   2828       GNUNET_PQ_result_spec_uint64 ("serial",
   2829                                     &td.serial),
   2830       GNUNET_PQ_result_spec_auto_from_type (
   2831         "h_payto",
   2832         &td.details.legitimization_processes.h_payto),
   2833       GNUNET_PQ_result_spec_timestamp (
   2834         "start_time",
   2835         &td.details.legitimization_processes.start_time),
   2836       GNUNET_PQ_result_spec_timestamp (
   2837         "expiration_time",
   2838         &td.details.legitimization_processes.expiration_time),
   2839       GNUNET_PQ_result_spec_uint64 (
   2840         "legitimization_measure_serial_id",
   2841         &td.details.legitimization_processes.legitimization_measure_serial_id),
   2842       GNUNET_PQ_result_spec_uint32 (
   2843         "measure_index",
   2844         &td.details.legitimization_processes.measure_index),
   2845       GNUNET_PQ_result_spec_string (
   2846         "provider_name",
   2847         &td.details.legitimization_processes.provider_name),
   2848       GNUNET_PQ_result_spec_string (
   2849         "provider_user_id",
   2850         &td.details.legitimization_processes.provider_user_id),
   2851       GNUNET_PQ_result_spec_string (
   2852         "provider_legitimization_id",
   2853         &td.details.legitimization_processes.provider_legitimization_id),
   2854       GNUNET_PQ_result_spec_string (
   2855         "redirect_url",
   2856         &td.details.legitimization_processes.redirect_url),
   2857       GNUNET_PQ_result_spec_end
   2858     };
   2859 
   2860     if (GNUNET_OK !=
   2861         GNUNET_PQ_extract_result (result,
   2862                                   rs,
   2863                                   i))
   2864     {
   2865       GNUNET_break (0);
   2866       ctx->error = true;
   2867       return;
   2868     }
   2869     ctx->cb (ctx->cb_cls,
   2870              &td);
   2871     GNUNET_PQ_cleanup_result (rs);
   2872   }
   2873 }
   2874 
   2875 
   2876 /**
   2877  * Function called with kyc_attributes table entries.
   2878  *
   2879  * @param cls closure
   2880  * @param result the postgres result
   2881  * @param num_results the number of results in @a result
   2882  */
   2883 static void
   2884 lrbt_cb_table_kyc_attributes (void *cls,
   2885                               PGresult *result,
   2886                               unsigned int num_results)
   2887 {
   2888   struct LookupRecordsByTableContext *ctx = cls;
   2889   struct TALER_EXCHANGEDB_TableData td = {
   2890     .table = TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES
   2891   };
   2892 
   2893   for (unsigned int i = 0; i<num_results; i++)
   2894   {
   2895     struct GNUNET_PQ_ResultSpec rs[] = {
   2896       GNUNET_PQ_result_spec_uint64 (
   2897         "kyc_attributes_serial_id",
   2898         &td.serial),
   2899       GNUNET_PQ_result_spec_auto_from_type (
   2900         "h_payto",
   2901         &td.details.kyc_attributes.h_payto),
   2902       GNUNET_PQ_result_spec_uint64 (
   2903         "legitimization_serial",
   2904         &td.details.kyc_attributes.legitimization_serial),
   2905       GNUNET_PQ_result_spec_timestamp (
   2906         "collection_time",
   2907         &td.details.kyc_attributes.collection_time),
   2908       GNUNET_PQ_result_spec_timestamp (
   2909         "expiration_time",
   2910         &td.details.kyc_attributes.expiration_time),
   2911       GNUNET_PQ_result_spec_uint64 (
   2912         "trigger_outcome_serial",
   2913         &td.details.kyc_attributes.trigger_outcome_serial),
   2914       GNUNET_PQ_result_spec_variable_size (
   2915         "encrypted_attributes",
   2916         &td.details.kyc_attributes.encrypted_attributes,
   2917         &td.details.kyc_attributes.encrypted_attributes_size),
   2918       GNUNET_PQ_result_spec_end
   2919     };
   2920 
   2921     if (GNUNET_OK !=
   2922         GNUNET_PQ_extract_result (result,
   2923                                   rs,
   2924                                   i))
   2925     {
   2926       GNUNET_break (0);
   2927       ctx->error = true;
   2928       return;
   2929     }
   2930     ctx->cb (ctx->cb_cls,
   2931              &td);
   2932     GNUNET_PQ_cleanup_result (rs);
   2933   }
   2934 }
   2935 
   2936 
   2937 /**
   2938  * Function called with aml_history table entries.
   2939  *
   2940  * @param cls closure
   2941  * @param result the postgres result
   2942  * @param num_results the number of results in @a result
   2943  */
   2944 static void
   2945 lrbt_cb_table_aml_history (void *cls,
   2946                            PGresult *result,
   2947                            unsigned int num_results)
   2948 {
   2949   struct LookupRecordsByTableContext *ctx = cls;
   2950   struct TALER_EXCHANGEDB_TableData td = {
   2951     .table = TALER_EXCHANGEDB_RT_AML_HISTORY
   2952   };
   2953 
   2954   for (unsigned int i = 0; i<num_results; i++)
   2955   {
   2956     struct GNUNET_PQ_ResultSpec rs[] = {
   2957       GNUNET_PQ_result_spec_uint64 (
   2958         "aml_history_serial_id",
   2959         &td.serial),
   2960       GNUNET_PQ_result_spec_auto_from_type (
   2961         "h_payto",
   2962         &td.details.aml_history.h_payto),
   2963       GNUNET_PQ_result_spec_uint64 (
   2964         "outcome_serial_id",
   2965         &td.details.aml_history.outcome_serial_id),
   2966       GNUNET_PQ_result_spec_string (
   2967         "justification",
   2968         &td.details.aml_history.justification),
   2969       GNUNET_PQ_result_spec_auto_from_type (
   2970         "decider_pub",
   2971         &td.details.aml_history.decider_pub),
   2972       GNUNET_PQ_result_spec_auto_from_type (
   2973         "decider_sig",
   2974         &td.details.aml_history.decider_sig),
   2975       GNUNET_PQ_result_spec_end
   2976     };
   2977 
   2978     if (GNUNET_OK !=
   2979         GNUNET_PQ_extract_result (result,
   2980                                   rs,
   2981                                   i))
   2982     {
   2983       GNUNET_break (0);
   2984       ctx->error = true;
   2985       return;
   2986     }
   2987     ctx->cb (ctx->cb_cls,
   2988              &td);
   2989     GNUNET_PQ_cleanup_result (rs);
   2990   }
   2991 }
   2992 
   2993 
   2994 /**
   2995  * Function called with kyc_events table entries.
   2996  *
   2997  * @param cls closure
   2998  * @param result the postgres result
   2999  * @param num_results the number of results in @a result
   3000  */
   3001 static void
   3002 lrbt_cb_table_kyc_events (void *cls,
   3003                           PGresult *result,
   3004                           unsigned int num_results)
   3005 {
   3006   struct LookupRecordsByTableContext *ctx = cls;
   3007   struct TALER_EXCHANGEDB_TableData td = {
   3008     .table = TALER_EXCHANGEDB_RT_KYC_EVENTS
   3009   };
   3010 
   3011   for (unsigned int i = 0; i<num_results; i++)
   3012   {
   3013     struct GNUNET_PQ_ResultSpec rs[] = {
   3014       GNUNET_PQ_result_spec_uint64 (
   3015         "kyc_event_serial_id",
   3016         &td.serial),
   3017       GNUNET_PQ_result_spec_timestamp (
   3018         "event_timestamp",
   3019         &td.details.kyc_events.event_timestamp),
   3020       GNUNET_PQ_result_spec_string (
   3021         "event_type",
   3022         &td.details.kyc_events.event_type),
   3023       GNUNET_PQ_result_spec_end
   3024     };
   3025 
   3026     if (GNUNET_OK !=
   3027         GNUNET_PQ_extract_result (result,
   3028                                   rs,
   3029                                   i))
   3030     {
   3031       GNUNET_break (0);
   3032       ctx->error = true;
   3033       return;
   3034     }
   3035     ctx->cb (ctx->cb_cls,
   3036              &td);
   3037     GNUNET_PQ_cleanup_result (rs);
   3038   }
   3039 }
   3040 
   3041 
   3042 /**
   3043  * Assign statement to @a n and PREPARE
   3044  * @a sql under name @a n.
   3045  */
   3046 #define XPREPARE(n,sql) \
   3047         statement = n;        \
   3048         PREPARE (pg, n, sql);
   3049 
   3050 
   3051 enum GNUNET_DB_QueryStatus
   3052 TEH_PG_lookup_records_by_table (void *cls,
   3053                                 enum TALER_EXCHANGEDB_ReplicatedTable table,
   3054                                 uint64_t serial,
   3055                                 TALER_EXCHANGEDB_ReplicationCallback cb,
   3056                                 void *cb_cls)
   3057 {
   3058   struct PostgresClosure *pg = cls;
   3059   struct GNUNET_PQ_QueryParam params[] = {
   3060     GNUNET_PQ_query_param_uint64 (&serial),
   3061     GNUNET_PQ_query_param_end
   3062   };
   3063   struct LookupRecordsByTableContext ctx = {
   3064     .pg = pg,
   3065     .cb = cb,
   3066     .cb_cls = cb_cls
   3067   };
   3068   GNUNET_PQ_PostgresResultHandler rh = NULL;
   3069   const char *statement = NULL;
   3070   enum GNUNET_DB_QueryStatus qs;
   3071 
   3072   switch (table)
   3073   {
   3074   case TALER_EXCHANGEDB_RT_DENOMINATIONS:
   3075     XPREPARE ("select_above_serial_by_table_denominations",
   3076               "SELECT"
   3077               " denominations_serial AS serial"
   3078               ",denom_type"
   3079               ",denom_pub"
   3080               ",master_sig"
   3081               ",valid_from"
   3082               ",expire_withdraw"
   3083               ",expire_deposit"
   3084               ",expire_legal"
   3085               ",coin"
   3086               ",fee_withdraw"
   3087               ",fee_deposit"
   3088               ",fee_refresh"
   3089               ",fee_refund"
   3090               ",age_mask"
   3091               " FROM denominations"
   3092               " WHERE denominations_serial > $1"
   3093               " ORDER BY denominations_serial ASC;");
   3094     rh = &lrbt_cb_table_denominations;
   3095     break;
   3096   case TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS:
   3097     XPREPARE ("select_above_serial_by_table_denomination_revocations",
   3098               "SELECT"
   3099               " denom_revocations_serial_id AS serial"
   3100               ",master_sig"
   3101               ",denominations_serial"
   3102               " FROM denomination_revocations"
   3103               " WHERE denom_revocations_serial_id > $1"
   3104               " ORDER BY denom_revocations_serial_id ASC;");
   3105     rh = &lrbt_cb_table_denomination_revocations;
   3106     break;
   3107   case TALER_EXCHANGEDB_RT_WIRE_TARGETS:
   3108     XPREPARE ("select_above_serial_by_table_wire_targets",
   3109               "SELECT"
   3110               " wire_target_serial_id AS serial"
   3111               ",payto_uri"
   3112               " FROM wire_targets"
   3113               " WHERE wire_target_serial_id > $1"
   3114               " ORDER BY wire_target_serial_id ASC;");
   3115     rh = &lrbt_cb_table_wire_targets;
   3116     break;
   3117   case TALER_EXCHANGEDB_RT_KYC_TARGETS:
   3118     XPREPARE ("select_above_serial_by_table_kyc_targets",
   3119               "SELECT"
   3120               " kyc_target_serial_id AS serial"
   3121               ",h_normalized_payto"
   3122               ",access_token"
   3123               ",target_pub"
   3124               ",is_wallet"
   3125               " FROM kyc_targets"
   3126               " WHERE kyc_target_serial_id > $1"
   3127               " ORDER BY kyc_target_serial_id ASC;");
   3128     rh = &lrbt_cb_table_kyc_targets;
   3129     break;
   3130   case TALER_EXCHANGEDB_RT_RESERVES:
   3131     XPREPARE ("select_above_serial_by_table_reserves",
   3132               "SELECT"
   3133               " reserve_uuid AS serial"
   3134               ",reserve_pub"
   3135               ",expiration_date"
   3136               ",gc_date"
   3137               " FROM reserves"
   3138               " WHERE reserve_uuid > $1"
   3139               " ORDER BY reserve_uuid ASC;");
   3140     rh = &lrbt_cb_table_reserves;
   3141     break;
   3142   case TALER_EXCHANGEDB_RT_RESERVES_IN:
   3143     XPREPARE ("select_above_serial_by_table_reserves_in",
   3144               "SELECT"
   3145               " reserve_in_serial_id AS serial"
   3146               ",reserve_pub"
   3147               ",wire_reference"
   3148               ",credit"
   3149               ",wire_source_h_payto"
   3150               ",exchange_account_section"
   3151               ",execution_date"
   3152               " FROM reserves_in"
   3153               " WHERE reserve_in_serial_id > $1"
   3154               " ORDER BY reserve_in_serial_id ASC;");
   3155     rh = &lrbt_cb_table_reserves_in;
   3156     break;
   3157   case TALER_EXCHANGEDB_RT_KYCAUTHS_IN:
   3158     XPREPARE ("select_above_serial_by_table_kycauth_in",
   3159               "SELECT"
   3160               " kycauth_in_serial_id AS serial"
   3161               ",account_pub"
   3162               ",wire_reference"
   3163               ",credit"
   3164               ",wire_source_h_payto"
   3165               ",exchange_account_section"
   3166               ",execution_date"
   3167               " FROM kycauths_in"
   3168               " WHERE kycauth_in_serial_id > $1"
   3169               " ORDER BY kycauth_in_serial_id ASC;");
   3170     rh = &lrbt_cb_table_kycauth_in;
   3171     break;
   3172   case TALER_EXCHANGEDB_RT_RESERVES_CLOSE:
   3173     XPREPARE ("select_above_serial_by_table_reserves_close",
   3174               "SELECT"
   3175               " close_uuid AS serial"
   3176               ",reserve_pub"
   3177               ",execution_date"
   3178               ",wtid"
   3179               ",wire_target_h_payto"
   3180               ",amount"
   3181               ",closing_fee"
   3182               " FROM reserves_close"
   3183               " WHERE close_uuid > $1"
   3184               " ORDER BY close_uuid ASC;");
   3185     rh = &lrbt_cb_table_reserves_close;
   3186     break;
   3187   case TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS:
   3188     XPREPARE ("select_above_serial_by_table_reserves_open_requests",
   3189               "SELECT"
   3190               " open_request_uuid AS serial"
   3191               ",reserve_pub"
   3192               ",request_timestamp"
   3193               ",expiration_date"
   3194               ",reserve_sig"
   3195               ",reserve_payment"
   3196               ",requested_purse_limit"
   3197               " FROM reserves_open_requests"
   3198               " WHERE open_request_uuid > $1"
   3199               " ORDER BY open_request_uuid ASC;");
   3200     rh = &lrbt_cb_table_reserves_open_requests;
   3201     break;
   3202   case TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS:
   3203     XPREPARE ("select_above_serial_by_table_reserves_open_deposits",
   3204               "SELECT"
   3205               " reserves_open_deposit_uuid AS serial"
   3206               ",reserve_sig"
   3207               ",reserve_pub"
   3208               ",coin_pub"
   3209               ",coin_sig"
   3210               ",contribution"
   3211               " FROM reserves_open_deposits"
   3212               " WHERE reserves_open_deposit_uuid > $1"
   3213               " ORDER BY reserves_open_deposit_uuid ASC;");
   3214     rh = &lrbt_cb_table_reserves_open_deposits;
   3215     break;
   3216   case TALER_EXCHANGEDB_RT_AUDITORS:
   3217     XPREPARE ("select_above_serial_by_table_auditors",
   3218               "SELECT"
   3219               " auditor_uuid AS serial"
   3220               ",auditor_pub"
   3221               ",auditor_name"
   3222               ",auditor_url"
   3223               ",is_active"
   3224               ",last_change"
   3225               " FROM auditors"
   3226               " WHERE auditor_uuid > $1"
   3227               " ORDER BY auditor_uuid ASC;");
   3228     rh = &lrbt_cb_table_auditors;
   3229     break;
   3230   case TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS:
   3231     XPREPARE ("select_above_serial_by_table_auditor_denom_sigs",
   3232               "SELECT"
   3233               " auditor_denom_serial AS serial"
   3234               ",auditor_uuid"
   3235               ",denominations_serial"
   3236               ",auditor_sig"
   3237               " FROM auditor_denom_sigs"
   3238               " WHERE auditor_denom_serial > $1"
   3239               " ORDER BY auditor_denom_serial ASC;");
   3240     rh = &lrbt_cb_table_auditor_denom_sigs;
   3241     break;
   3242   case TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS:
   3243     XPREPARE ("select_above_serial_by_table_exchange_sign_keys",
   3244               "SELECT"
   3245               " esk_serial AS serial"
   3246               ",exchange_pub"
   3247               ",master_sig"
   3248               ",valid_from"
   3249               ",expire_sign"
   3250               ",expire_legal"
   3251               " FROM exchange_sign_keys"
   3252               " WHERE esk_serial > $1"
   3253               " ORDER BY esk_serial ASC;");
   3254     rh = &lrbt_cb_table_exchange_sign_keys;
   3255     break;
   3256   case TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS:
   3257     XPREPARE ("select_above_serial_by_table_signkey_revocations",
   3258               "SELECT"
   3259               " signkey_revocations_serial_id AS serial"
   3260               ",esk_serial"
   3261               ",master_sig"
   3262               " FROM signkey_revocations"
   3263               " WHERE signkey_revocations_serial_id > $1"
   3264               " ORDER BY signkey_revocations_serial_id ASC;");
   3265     rh = &lrbt_cb_table_signkey_revocations;
   3266     break;
   3267   case TALER_EXCHANGEDB_RT_KNOWN_COINS:
   3268     XPREPARE ("select_above_serial_by_table_known_coins",
   3269               "SELECT"
   3270               " known_coin_id AS serial"
   3271               ",coin_pub"
   3272               ",denom_sig"
   3273               ",denominations_serial"
   3274               " FROM known_coins"
   3275               " WHERE known_coin_id > $1"
   3276               " ORDER BY known_coin_id ASC;");
   3277     rh = &lrbt_cb_table_known_coins;
   3278     break;
   3279   case TALER_EXCHANGEDB_RT_REFRESH:
   3280     XPREPARE ("select_above_serial_by_table_refresh",
   3281               "SELECT"
   3282               " refresh_id AS serial"
   3283               ",rc"
   3284               ",execution_date"
   3285               ",amount_with_fee"
   3286               ",old_coin_pub"
   3287               ",old_coin_sig"
   3288               ",refresh_seed"
   3289               ",noreveal_index"
   3290               ",planchets_h"
   3291               ",selected_h"
   3292               ",blinding_seed"
   3293               ",cs_r_values"
   3294               ",cs_r_choices"
   3295               ",denom_serials"
   3296               ",denom_sigs"
   3297               " FROM refresh"
   3298               " WHERE refresh_id > $1"
   3299               " ORDER BY refresh_id ASC;");
   3300     rh = &lrbt_cb_table_refresh;
   3301     break;
   3302   case TALER_EXCHANGEDB_RT_BATCH_DEPOSITS:
   3303     XPREPARE ("select_above_serial_by_table_batch_deposits",
   3304               "SELECT"
   3305               " batch_deposit_serial_id AS serial"
   3306               ",shard"
   3307               ",merchant_pub"
   3308               ",wallet_timestamp"
   3309               ",exchange_timestamp"
   3310               ",refund_deadline"
   3311               ",wire_deadline"
   3312               ",h_contract_terms"
   3313               ",wallet_data_hash"
   3314               ",wire_salt"
   3315               ",wire_target_h_payto"
   3316               ",policy_details_serial_id"
   3317               ",policy_blocked"
   3318               ",total_amount"
   3319               ",merchant_sig"
   3320               ",done"
   3321               " FROM batch_deposits"
   3322               " WHERE batch_deposit_serial_id > $1"
   3323               " ORDER BY batch_deposit_serial_id ASC;");
   3324     rh = &lrbt_cb_table_batch_deposits;
   3325     break;
   3326   case TALER_EXCHANGEDB_RT_COIN_DEPOSITS:
   3327     XPREPARE ("select_above_serial_by_table_coin_deposits",
   3328               "SELECT"
   3329               " coin_deposit_serial_id AS serial"
   3330               ",batch_deposit_serial_id"
   3331               ",coin_pub"
   3332               ",coin_sig"
   3333               ",amount_with_fee"
   3334               " FROM coin_deposits"
   3335               " WHERE coin_deposit_serial_id > $1"
   3336               " ORDER BY coin_deposit_serial_id ASC;");
   3337     rh = &lrbt_cb_table_coin_deposits;
   3338     break;
   3339   case TALER_EXCHANGEDB_RT_REFUNDS:
   3340     XPREPARE ("select_above_serial_by_table_refunds",
   3341               "SELECT"
   3342               " refund_serial_id AS serial"
   3343               ",coin_pub"
   3344               ",merchant_sig"
   3345               ",rtransaction_id"
   3346               ",amount_with_fee"
   3347               ",batch_deposit_serial_id"
   3348               " FROM refunds"
   3349               " WHERE refund_serial_id > $1"
   3350               " ORDER BY refund_serial_id ASC;");
   3351     rh = &lrbt_cb_table_refunds;
   3352     break;
   3353   case TALER_EXCHANGEDB_RT_WIRE_OUT:
   3354     XPREPARE ("select_above_serial_by_table_wire_out",
   3355               "SELECT"
   3356               " wireout_uuid AS serial"
   3357               ",execution_date"
   3358               ",wtid_raw"
   3359               ",wire_target_h_payto"
   3360               ",exchange_account_section"
   3361               ",amount"
   3362               " FROM wire_out"
   3363               " WHERE wireout_uuid > $1"
   3364               " ORDER BY wireout_uuid ASC;");
   3365     rh = &lrbt_cb_table_wire_out;
   3366     break;
   3367   case TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING:
   3368     XPREPARE ("select_above_serial_by_table_aggregation_tracking",
   3369               "SELECT"
   3370               " aggregation_serial_id AS serial"
   3371               ",batch_deposit_serial_id"
   3372               ",wtid_raw"
   3373               " FROM aggregation_tracking"
   3374               " WHERE aggregation_serial_id > $1"
   3375               " ORDER BY aggregation_serial_id ASC;");
   3376     rh = &lrbt_cb_table_aggregation_tracking;
   3377     break;
   3378   case TALER_EXCHANGEDB_RT_WIRE_FEE:
   3379     XPREPARE ("select_above_serial_by_table_wire_fee",
   3380               "SELECT"
   3381               " wire_fee_serial AS serial"
   3382               ",wire_method"
   3383               ",start_date"
   3384               ",end_date"
   3385               ",wire_fee"
   3386               ",closing_fee"
   3387               ",master_sig"
   3388               " FROM wire_fee"
   3389               " WHERE wire_fee_serial > $1"
   3390               " ORDER BY wire_fee_serial ASC;");
   3391     rh = &lrbt_cb_table_wire_fee;
   3392     break;
   3393   case TALER_EXCHANGEDB_RT_GLOBAL_FEE:
   3394     XPREPARE ("select_above_serial_by_table_global_fee",
   3395               "SELECT"
   3396               " global_fee_serial AS serial"
   3397               ",start_date"
   3398               ",end_date"
   3399               ",history_fee"
   3400               ",account_fee"
   3401               ",purse_fee"
   3402               ",purse_timeout"
   3403               ",history_expiration"
   3404               ",purse_account_limit"
   3405               ",master_sig"
   3406               " FROM global_fee"
   3407               " WHERE global_fee_serial > $1"
   3408               " ORDER BY global_fee_serial ASC;");
   3409     rh = &lrbt_cb_table_global_fee;
   3410     break;
   3411   case TALER_EXCHANGEDB_RT_RECOUP:
   3412     XPREPARE ("select_above_serial_by_table_recoup",
   3413               "SELECT"
   3414               " recoup_uuid AS serial"
   3415               ",coin_sig"
   3416               ",coin_blind"
   3417               ",amount"
   3418               ",recoup_timestamp"
   3419               ",coin_pub"
   3420               ",reserve_out_serial_id"
   3421               " FROM recoup"
   3422               " WHERE recoup_uuid > $1"
   3423               " ORDER BY recoup_uuid ASC;");
   3424     rh = &lrbt_cb_table_recoup;
   3425     break;
   3426   case TALER_EXCHANGEDB_RT_RECOUP_REFRESH:
   3427     XPREPARE ("select_above_serial_by_table_recoup_refresh",
   3428               "SELECT"
   3429               " recoup_refresh_uuid AS serial"
   3430               ",coin_sig"
   3431               ",coin_blind"
   3432               ",amount"
   3433               ",recoup_timestamp"
   3434               ",coin_pub"
   3435               ",known_coin_id"
   3436               ",rrc_serial"
   3437               " FROM recoup_refresh"
   3438               " WHERE recoup_refresh_uuid > $1"
   3439               " ORDER BY recoup_refresh_uuid ASC;");
   3440     rh = &lrbt_cb_table_recoup_refresh;
   3441     break;
   3442   case TALER_EXCHANGEDB_RT_EXTENSIONS:
   3443     // FIXME: this seems broken! -- where is the SQL!?
   3444     statement = "select_above_serial_by_table_extensions";
   3445     rh = &lrbt_cb_table_extensions;
   3446     break;
   3447   case TALER_EXCHANGEDB_RT_POLICY_DETAILS:
   3448     // FIXME: this seems broken! -- where is the SQL!?
   3449     statement = "select_above_serial_by_table_policy_details";
   3450     rh = &lrbt_cb_table_policy_details;
   3451     break;
   3452   case TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS:
   3453     // FIXME: this seems broken! -- where is the SQL!?
   3454     statement = "select_above_serial_by_table_policy_fulfillments";
   3455     rh = &lrbt_cb_table_policy_fulfillments;
   3456     break;
   3457   case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
   3458     XPREPARE ("select_above_serial_by_table_purse_requests",
   3459               "SELECT"
   3460               " purse_requests_serial_id"
   3461               ",purse_pub"
   3462               ",merge_pub"
   3463               ",purse_creation"
   3464               ",purse_expiration"
   3465               ",h_contract_terms"
   3466               ",age_limit"
   3467               ",flags"
   3468               ",amount_with_fee"
   3469               ",purse_fee"
   3470               ",purse_sig"
   3471               " FROM purse_requests"
   3472               " WHERE purse_requests_serial_id > $1"
   3473               " ORDER BY purse_requests_serial_id ASC;");
   3474     rh = &lrbt_cb_table_purse_requests;
   3475     break;
   3476   case TALER_EXCHANGEDB_RT_PURSE_DECISION:
   3477     XPREPARE ("select_above_serial_by_table_purse_decision",
   3478               "SELECT"
   3479               " purse_decision_serial_id"
   3480               ",action_timestamp"
   3481               ",refunded"
   3482               ",purse_pub"
   3483               " FROM purse_decision"
   3484               " WHERE purse_decision_serial_id > $1"
   3485               " ORDER BY purse_decision_serial_id ASC;");
   3486     rh = &lrbt_cb_table_purse_decision;
   3487     break;
   3488   case TALER_EXCHANGEDB_RT_PURSE_MERGES:
   3489     XPREPARE ("select_above_serial_by_table_purse_merges",
   3490               "SELECT"
   3491               " purse_merge_request_serial_id"
   3492               ",partner_serial_id"
   3493               ",reserve_pub"
   3494               ",purse_pub"
   3495               ",merge_sig"
   3496               ",merge_timestamp"
   3497               " FROM purse_merges"
   3498               " WHERE purse_merge_request_serial_id > $1"
   3499               " ORDER BY purse_merge_request_serial_id ASC;");
   3500     rh = &lrbt_cb_table_purse_merges;
   3501     break;
   3502   case TALER_EXCHANGEDB_RT_PURSE_DEPOSITS:
   3503     XPREPARE ("select_above_serial_by_table_purse_deposits",
   3504               "SELECT"
   3505               " purse_deposit_serial_id"
   3506               ",partner_serial_id"
   3507               ",purse_pub"
   3508               ",coin_pub"
   3509               ",amount_with_fee"
   3510               ",coin_sig"
   3511               " FROM purse_deposits"
   3512               " WHERE purse_deposit_serial_id > $1"
   3513               " ORDER BY purse_deposit_serial_id ASC;");
   3514     rh = &lrbt_cb_table_purse_deposits;
   3515     break;
   3516   case TALER_EXCHANGEDB_RT_ACCOUNT_MERGES:
   3517     XPREPARE ("select_above_serial_by_table_account_merges",
   3518               "SELECT"
   3519               " account_merge_request_serial_id"
   3520               ",reserve_pub"
   3521               ",reserve_sig"
   3522               ",purse_pub"
   3523               ",wallet_h_payto"
   3524               " FROM account_merges"
   3525               " WHERE account_merge_request_serial_id > $1"
   3526               " ORDER BY account_merge_request_serial_id ASC;");
   3527     rh = &lrbt_cb_table_account_merges;
   3528     break;
   3529   case TALER_EXCHANGEDB_RT_HISTORY_REQUESTS:
   3530     XPREPARE ("select_above_serial_by_table_history_requests",
   3531               "SELECT"
   3532               " history_request_serial_id"
   3533               ",reserve_pub"
   3534               ",request_timestamp"
   3535               ",reserve_sig"
   3536               ",history_fee"
   3537               " FROM history_requests"
   3538               " WHERE history_request_serial_id > $1"
   3539               " ORDER BY history_request_serial_id ASC;");
   3540     rh = &lrbt_cb_table_history_requests;
   3541     break;
   3542   case TALER_EXCHANGEDB_RT_CLOSE_REQUESTS:
   3543     XPREPARE ("select_above_serial_by_table_close_requests",
   3544               "SELECT"
   3545               " close_request_serial_id"
   3546               ",reserve_pub"
   3547               ",close_timestamp"
   3548               ",reserve_sig"
   3549               ",close"
   3550               " FROM close_requests"
   3551               " WHERE close_request_serial_id > $1"
   3552               " ORDER BY close_request_serial_id ASC;");
   3553     rh = &lrbt_cb_table_close_requests;
   3554     break;
   3555   case TALER_EXCHANGEDB_RT_WADS_OUT:
   3556     XPREPARE ("select_above_serial_by_table_wads_out",
   3557               "SELECT"
   3558               " wad_out_serial_id"
   3559               ",wad_id"
   3560               ",partner_serial_id"
   3561               ",amount"
   3562               ",execution_time"
   3563               " FROM wads_out"
   3564               " WHERE wad_out_serial_id > $1"
   3565               " ORDER BY wad_out_serial_id ASC;");
   3566     rh = &lrbt_cb_table_wads_out;
   3567     break;
   3568   case TALER_EXCHANGEDB_RT_WADS_OUT_ENTRIES:
   3569     XPREPARE ("select_above_serial_by_table_wads_out_entries",
   3570               "SELECT"
   3571               " wad_out_entry_serial_id"
   3572               ",reserve_pub"
   3573               ",purse_pub"
   3574               ",h_contract"
   3575               ",purse_expiration"
   3576               ",merge_timestamp"
   3577               ",amount_with_fee"
   3578               ",wad_fee"
   3579               ",deposit_fees"
   3580               ",reserve_sig"
   3581               ",purse_sig"
   3582               " FROM wad_out_entries"
   3583               " WHERE wad_out_entry_serial_id > $1"
   3584               " ORDER BY wad_out_entry_serial_id ASC;");
   3585     rh = &lrbt_cb_table_wads_out_entries;
   3586     break;
   3587   case TALER_EXCHANGEDB_RT_WADS_IN:
   3588     XPREPARE ("select_above_serial_by_table_wads_in",
   3589               "SELECT"
   3590               " wad_in_serial_id"
   3591               ",wad_id"
   3592               ",origin_exchange_url"
   3593               ",amount"
   3594               ",arrival_time"
   3595               " FROM wads_in"
   3596               " WHERE wad_in_serial_id > $1"
   3597               " ORDER BY wad_in_serial_id ASC;");
   3598     rh = &lrbt_cb_table_wads_in;
   3599     break;
   3600   case TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES:
   3601     XPREPARE ("select_above_serial_by_table_wads_in_entries",
   3602               "SELECT"
   3603               " wad_in_entry_serial_id"
   3604               ",reserve_pub"
   3605               ",purse_pub"
   3606               ",h_contract"
   3607               ",purse_expiration"
   3608               ",merge_timestamp"
   3609               ",amount_with_fee"
   3610               ",wad_fee"
   3611               ",deposit_fees"
   3612               ",reserve_sig"
   3613               ",purse_sig"
   3614               " FROM wad_in_entries"
   3615               " WHERE wad_in_entry_serial_id > $1"
   3616               " ORDER BY wad_in_entry_serial_id ASC;");
   3617     rh = &lrbt_cb_table_wads_in_entries;
   3618     break;
   3619   case TALER_EXCHANGEDB_RT_PROFIT_DRAINS:
   3620     XPREPARE ("select_above_serial_by_table_profit_drains",
   3621               "SELECT"
   3622               " profit_drain_serial_id"
   3623               ",wtid"
   3624               ",account_section"
   3625               ",payto_uri"
   3626               ",trigger_date"
   3627               ",amount"
   3628               ",master_sig"
   3629               " FROM profit_drains"
   3630               " WHERE profit_drain_serial_id > $1"
   3631               " ORDER BY profit_drain_serial_id ASC;");
   3632     rh = &lrbt_cb_table_profit_drains;
   3633     break;
   3634 
   3635   case TALER_EXCHANGEDB_RT_AML_STAFF:
   3636     XPREPARE ("select_above_serial_by_table_aml_staff",
   3637               "SELECT"
   3638               " aml_staff_uuid"
   3639               ",decider_pub"
   3640               ",master_sig"
   3641               ",decider_name"
   3642               ",is_active"
   3643               ",read_only"
   3644               ",last_change"
   3645               " FROM aml_staff"
   3646               " WHERE aml_staff_uuid > $1"
   3647               " ORDER BY aml_staff_uuid ASC;");
   3648     rh = &lrbt_cb_table_aml_staff;
   3649     break;
   3650   case TALER_EXCHANGEDB_RT_PURSE_DELETION:
   3651     XPREPARE ("select_above_serial_by_table_purse_deletion",
   3652               "SELECT"
   3653               " purse_deletion_serial_id"
   3654               ",purse_pub"
   3655               ",purse_sig"
   3656               " FROM purse_deletion"
   3657               " WHERE purse_deletion_serial_id > $1"
   3658               " ORDER BY purse_deletion_serial_id ASC;");
   3659     rh = &lrbt_cb_table_purse_deletion;
   3660     break;
   3661   case TALER_EXCHANGEDB_RT_WITHDRAW:
   3662     XPREPARE ("select_above_serial_by_table_withdraw",
   3663               "SELECT"
   3664               " withdraw_id"
   3665               ",planchets_h"
   3666               ",execution_date"
   3667               ",amount_with_fee"
   3668               ",reserve_pub"
   3669               ",reserve_sig"
   3670               ",max_age"
   3671               ",noreveal_index"
   3672               ",selected_h"
   3673               ",blinding_seed"
   3674               ",cs_r_values"
   3675               ",cs_r_choices"
   3676               ",denom_serials"
   3677               ",denom_sigs"
   3678               " FROM withdraw"
   3679               " WHERE withdraw_id > $1"
   3680               " ORDER BY withdraw_id ASC;");
   3681     rh = &lrbt_cb_table_withdraw;
   3682     break;
   3683   case TALER_EXCHANGEDB_RT_LEGITIMIZATION_MEASURES:
   3684     XPREPARE ("select_above_serial_by_table_legitimization_measures",
   3685               "SELECT"
   3686               " legitimization_measure_serial_id AS serial"
   3687               ",access_token"
   3688               ",start_time"
   3689               ",jmeasures::TEXT"
   3690               ",display_priority"
   3691               " FROM legitimization_measures"
   3692               " WHERE legitimization_measure_serial_id > $1"
   3693               " ORDER BY legitimization_measure_serial_id ASC;");
   3694     rh = &lrbt_cb_table_legitimization_measures;
   3695     break;
   3696   case TALER_EXCHANGEDB_RT_LEGITIMIZATION_OUTCOMES:
   3697     XPREPARE ("select_above_serial_by_table_legitimization_outcomes",
   3698               "SELECT"
   3699               " outcome_serial_id AS serial"
   3700               ",h_payto"
   3701               ",decision_time"
   3702               ",expiration_time"
   3703               ",jproperties::TEXT"
   3704               ",to_investigate"
   3705               ",jnew_rules::TEXT"
   3706               " FROM legitimization_outcomes"
   3707               " WHERE outcome_serial_id > $1"
   3708               " ORDER BY outcome_serial_id ASC;");
   3709     rh = &lrbt_cb_table_legitimization_outcomes;
   3710     break;
   3711   case TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES:
   3712     XPREPARE ("select_above_serial_by_table_legitimization_processes",
   3713               "SELECT"
   3714               " legitimization_process_serial_id AS serial"
   3715               ",h_payto"
   3716               ",start_time"
   3717               ",expiration_time"
   3718               ",legitimization_measure_serial_id"
   3719               ",measure_index"
   3720               ",provider_name"
   3721               ",provider_user_id"
   3722               ",provider_legitimization_id"
   3723               ",redirect_url"
   3724               " FROM legitimization_processes"
   3725               " WHERE legitimization_process_serial_id > $1"
   3726               " ORDER BY legitimization_process_serial_id ASC;");
   3727     rh = &lrbt_cb_table_legitimization_processes;
   3728     break;
   3729   case TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES:
   3730     XPREPARE ("select_above_serial_by_table_kyc_attributes",
   3731               "SELECT"
   3732               " kyc_attributes_serial_id"
   3733               ",h_payto"
   3734               ",legitimization_serial"
   3735               ",collection_time"
   3736               ",expiration_time"
   3737               ",trigger_outcome_serial"
   3738               ",encrypted_attributes"
   3739               " FROM kyc_attributes"
   3740               " WHERE kyc_attributes_serial_id > $1"
   3741               " ORDER BY kyc_attributes_serial_id ASC;");
   3742     rh = &lrbt_cb_table_kyc_attributes;
   3743     break;
   3744   case TALER_EXCHANGEDB_RT_AML_HISTORY:
   3745     XPREPARE ("select_above_serial_by_table_aml_history",
   3746               "SELECT"
   3747               " aml_history_serial_id"
   3748               ",h_payto"
   3749               ",outcome_serial_id"
   3750               ",justification"
   3751               ",decider_pub"
   3752               ",decider_sig"
   3753               " FROM aml_history"
   3754               " WHERE aml_history_serial_id > $1"
   3755               " ORDER BY aml_history_serial_id ASC;");
   3756     rh = &lrbt_cb_table_aml_history;
   3757     break;
   3758   case TALER_EXCHANGEDB_RT_KYC_EVENTS:
   3759     XPREPARE ("select_above_serial_by_table_kyc_events",
   3760               "SELECT"
   3761               " kyc_event_serial_id AS serial"
   3762               ",event_timestamp"
   3763               ",event_type"
   3764               " FROM kyc_events"
   3765               " WHERE kyc_event_serial_id > $1"
   3766               " ORDER BY kyc_event_serial_id ASC;");
   3767     rh = &lrbt_cb_table_kyc_events;
   3768     break;
   3769   }
   3770   if (NULL == rh)
   3771   {
   3772     GNUNET_break (0);
   3773     return GNUNET_DB_STATUS_HARD_ERROR;
   3774   }
   3775 
   3776   qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
   3777                                              statement,
   3778                                              params,
   3779                                              rh,
   3780                                              &ctx);
   3781   if (qs < 0)
   3782   {
   3783     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3784                 "Failed to run `%s'\n",
   3785                 statement);
   3786     return qs;
   3787   }
   3788   if (ctx.error)
   3789   {
   3790     GNUNET_break (0);
   3791     return GNUNET_DB_STATUS_HARD_ERROR;
   3792   }
   3793   return qs;
   3794 }
   3795 
   3796 
   3797 #undef XPREPARE
   3798 
   3799 /* end of pg_lookup_records_by_table.c */