exchange

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

lookup_records_by_table.c (108721B)


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