exchange

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

iterate_records_by_table.c (112459B)


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