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


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