exchange

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

pq_query_helper.c (34984B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2023 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file pq/pq_query_helper.c
     18  * @brief helper functions for Taler-specific libpq (PostGres) interactions
     19  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
     20  * @author Florian Dold
     21  * @author Christian Grothoff
     22  */
     23 #include <gnunet/gnunet_common.h>
     24 #include <gnunet/gnunet_util_lib.h>
     25 #include <gnunet/gnunet_pq_lib.h>
     26 #include "taler/taler_pq_lib.h"
     27 #include "pq_common.h"
     28 
     29 
     30 /**
     31  * Function called to convert input amount into SQL parameter as tuple.
     32  *
     33  * @param cls closure
     34  * @param data pointer to input argument, here a `struct TALER_Amount`
     35  * @param data_len number of bytes in @a data (if applicable)
     36  * @param[out] param_values SQL data to set
     37  * @param[out] param_lengths SQL length data to set
     38  * @param[out] param_formats SQL format data to set
     39  * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
     40  * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc()
     41  * @param scratch_length number of entries left in @a scratch
     42  * @return -1 on error, number of offsets used in @a scratch otherwise
     43  */
     44 static int
     45 qconv_amount_currency_tuple (void *cls,
     46                              const void *data,
     47                              size_t data_len,
     48                              void *param_values[],
     49                              int param_lengths[],
     50                              int param_formats[],
     51                              unsigned int param_length,
     52                              void *scratch[],
     53                              unsigned int scratch_length)
     54 {
     55   struct GNUNET_PQ_Context *db = cls;
     56   const struct TALER_Amount *amount = data;
     57   size_t sz;
     58 
     59   GNUNET_assert (NULL != db);
     60   GNUNET_assert (NULL != amount);
     61   GNUNET_assert (1 == param_length);
     62   GNUNET_assert (1 <= scratch_length);
     63   GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
     64   GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid));
     65   {
     66     char *out;
     67     Oid oid_v;
     68     Oid oid_f;
     69     Oid oid_c;
     70     struct TALER_PQ_AmountCurrencyP d;
     71 
     72     GNUNET_assert (GNUNET_OK ==
     73                    GNUNET_PQ_get_oid_by_name (db,
     74                                               "int8",
     75                                               &oid_v));
     76     GNUNET_assert (GNUNET_OK ==
     77                    GNUNET_PQ_get_oid_by_name (db,
     78                                               "int4",
     79                                               &oid_f));
     80     GNUNET_assert (GNUNET_OK ==
     81                    GNUNET_PQ_get_oid_by_name (db,
     82                                               "varchar",
     83                                               &oid_c));
     84     sz = TALER_PQ_make_taler_pq_amount_currency_ (amount,
     85                                                   oid_v,
     86                                                   oid_f,
     87                                                   oid_c,
     88                                                   &d);
     89     out = GNUNET_malloc (sz);
     90     memcpy (out,
     91             &d,
     92             sz);
     93     scratch[0] = out;
     94   }
     95 
     96   param_values[0] = scratch[0];
     97   param_lengths[0] = sz;
     98   param_formats[0] = 1;
     99 
    100   return 1;
    101 }
    102 
    103 
    104 struct GNUNET_PQ_QueryParam
    105 TALER_PQ_query_param_amount_with_currency (
    106   const struct GNUNET_PQ_Context *db,
    107   const struct TALER_Amount *amount)
    108 {
    109   struct GNUNET_PQ_QueryParam res = {
    110     .conv_cls = (void *) db,
    111     .conv = &qconv_amount_currency_tuple,
    112     .data = amount,
    113     .size = sizeof (*amount),
    114     .num_params = 1,
    115   };
    116 
    117   return res;
    118 }
    119 
    120 
    121 /**
    122  * Function called to convert input amount into SQL parameter as tuple.
    123  *
    124  * @param cls closure
    125  * @param data pointer to input argument, here a `struct TALER_Amount`
    126  * @param data_len number of bytes in @a data (if applicable)
    127  * @param[out] param_values SQL data to set
    128  * @param[out] param_lengths SQL length data to set
    129  * @param[out] param_formats SQL format data to set
    130  * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
    131  * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc()
    132  * @param scratch_length number of entries left in @a scratch
    133  * @return -1 on error, number of offsets used in @a scratch otherwise
    134  */
    135 static int
    136 qconv_amount_tuple (void *cls,
    137                     const void *data,
    138                     size_t data_len,
    139                     void *param_values[],
    140                     int param_lengths[],
    141                     int param_formats[],
    142                     unsigned int param_length,
    143                     void *scratch[],
    144                     unsigned int scratch_length)
    145 {
    146   struct GNUNET_PQ_Context *db = cls;
    147   const struct TALER_Amount *amount = data;
    148   size_t sz;
    149 
    150   GNUNET_assert (NULL != db);
    151   GNUNET_assert (NULL != amount);
    152   GNUNET_assert (1 == param_length);
    153   GNUNET_assert (1 <= scratch_length);
    154   GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
    155   GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid));
    156   {
    157     char *out;
    158     Oid oid_v;
    159     Oid oid_f;
    160 
    161     GNUNET_assert (GNUNET_OK ==
    162                    GNUNET_PQ_get_oid_by_name (db,
    163                                               "int8",
    164                                               &oid_v));
    165     GNUNET_assert (GNUNET_OK ==
    166                    GNUNET_PQ_get_oid_by_name (db,
    167                                               "int4",
    168                                               &oid_f));
    169 
    170     {
    171       struct TALER_PQ_AmountP d
    172         = TALER_PQ_make_taler_pq_amount_ (amount,
    173                                           oid_v,
    174                                           oid_f);
    175 
    176       sz = sizeof(d);
    177       out = GNUNET_malloc (sz);
    178       scratch[0] = out;
    179       GNUNET_memcpy (out,
    180                      &d,
    181                      sizeof(d));
    182     }
    183   }
    184 
    185   param_values[0] = scratch[0];
    186   param_lengths[0] = sz;
    187   param_formats[0] = 1;
    188 
    189   return 1;
    190 }
    191 
    192 
    193 struct GNUNET_PQ_QueryParam
    194 TALER_PQ_query_param_amount (
    195   const struct GNUNET_PQ_Context *db,
    196   const struct TALER_Amount *amount)
    197 {
    198   struct GNUNET_PQ_QueryParam res = {
    199     .conv_cls = (void *) db,
    200     .conv = &qconv_amount_tuple,
    201     .data = amount,
    202     .size = sizeof (*amount),
    203     .num_params = 1,
    204   };
    205 
    206   return res;
    207 }
    208 
    209 
    210 /**
    211  * Function called to convert input argument into SQL parameters.
    212  *
    213  * @param cls closure
    214  * @param data pointer to input argument
    215  * @param data_len number of bytes in @a data (if applicable)
    216  * @param[out] param_values SQL data to set
    217  * @param[out] param_lengths SQL length data to set
    218  * @param[out] param_formats SQL format data to set
    219  * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
    220  * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
    221  * @param scratch_length number of entries left in @a scratch
    222  * @return -1 on error, number of offsets used in @a scratch otherwise
    223  */
    224 static int
    225 qconv_denom_pub (void *cls,
    226                  const void *data,
    227                  size_t data_len,
    228                  void *param_values[],
    229                  int param_lengths[],
    230                  int param_formats[],
    231                  unsigned int param_length,
    232                  void *scratch[],
    233                  unsigned int scratch_length)
    234 {
    235   const struct TALER_DenominationPublicKey *denom_pub = data;
    236   const struct GNUNET_CRYPTO_BlindSignPublicKey *bsp = denom_pub->bsign_pub_key;
    237   size_t tlen;
    238   size_t len;
    239   uint32_t be[2];
    240   char *buf;
    241   void *tbuf;
    242 
    243   (void) cls;
    244   (void) data_len;
    245   GNUNET_assert (1 == param_length);
    246   GNUNET_assert (scratch_length > 0);
    247   GNUNET_break (NULL == cls);
    248   be[0] = htonl ((uint32_t) bsp->cipher);
    249   be[1] = htonl (denom_pub->age_mask.bits);
    250   switch (bsp->cipher)
    251   {
    252   case GNUNET_CRYPTO_BSA_RSA:
    253     tlen = GNUNET_CRYPTO_rsa_public_key_encode (
    254       bsp->details.rsa_public_key,
    255       &tbuf);
    256     break;
    257   case GNUNET_CRYPTO_BSA_CS:
    258     tlen = sizeof (bsp->details.cs_public_key);
    259     break;
    260   default:
    261     GNUNET_assert (0);
    262   }
    263   len = tlen + sizeof (be);
    264   buf = GNUNET_malloc (len);
    265   GNUNET_memcpy (buf,
    266                  be,
    267                  sizeof (be));
    268   switch (bsp->cipher)
    269   {
    270   case GNUNET_CRYPTO_BSA_RSA:
    271     GNUNET_memcpy (&buf[sizeof (be)],
    272                    tbuf,
    273                    tlen);
    274     GNUNET_free (tbuf);
    275     break;
    276   case GNUNET_CRYPTO_BSA_CS:
    277     GNUNET_memcpy (&buf[sizeof (be)],
    278                    &bsp->details.cs_public_key,
    279                    tlen);
    280     break;
    281   default:
    282     GNUNET_assert (0);
    283   }
    284 
    285   scratch[0] = buf;
    286   param_values[0] = (void *) buf;
    287   param_lengths[0] = len;
    288   param_formats[0] = 1;
    289   return 1;
    290 }
    291 
    292 
    293 struct GNUNET_PQ_QueryParam
    294 TALER_PQ_query_param_denom_pub (
    295   const struct TALER_DenominationPublicKey *denom_pub)
    296 {
    297   struct GNUNET_PQ_QueryParam res = {
    298     .conv = &qconv_denom_pub,
    299     .data = denom_pub,
    300     .num_params = 1
    301   };
    302 
    303   return res;
    304 }
    305 
    306 
    307 struct GNUNET_PQ_QueryParam
    308 TALER_PQ_query_param_denom_sig (
    309   const struct TALER_DenominationSignature *denom_sig)
    310 {
    311   return GNUNET_PQ_query_param_unblinded_sig (denom_sig->unblinded_sig);
    312 }
    313 
    314 
    315 struct GNUNET_PQ_QueryParam
    316 TALER_PQ_query_param_blinded_denom_sig (
    317   const struct TALER_BlindedDenominationSignature *denom_sig)
    318 {
    319   return GNUNET_PQ_query_param_blinded_sig (denom_sig->blinded_sig);
    320 }
    321 
    322 
    323 /**
    324  * Function called to convert input argument into SQL parameters.
    325  *
    326  * @param cls closure
    327  * @param data pointer to input argument
    328  * @param data_len number of bytes in @a data (if applicable)
    329  * @param[out] param_values SQL data to set
    330  * @param[out] param_lengths SQL length data to set
    331  * @param[out] param_formats SQL format data to set
    332  * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
    333  * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
    334  * @param scratch_length number of entries left in @a scratch
    335  * @return -1 on error, number of offsets used in @a scratch otherwise
    336  */
    337 static int
    338 qconv_blinded_planchet (void *cls,
    339                         const void *data,
    340                         size_t data_len,
    341                         void *param_values[],
    342                         int param_lengths[],
    343                         int param_formats[],
    344                         unsigned int param_length,
    345                         void *scratch[],
    346                         unsigned int scratch_length)
    347 {
    348   const struct TALER_BlindedPlanchet *bp = data;
    349   const struct GNUNET_CRYPTO_BlindedMessage *bm = bp->blinded_message;
    350   size_t tlen;
    351   size_t len;
    352   uint32_t be[2];
    353   char *buf;
    354 
    355   (void) cls;
    356   (void) data_len;
    357   GNUNET_assert (1 == param_length);
    358   GNUNET_assert (scratch_length > 0);
    359   GNUNET_break (NULL == cls);
    360   be[0] = htonl ((uint32_t) bm->cipher);
    361   be[1] = htonl (0x0100); /* magic marker: blinded */
    362   switch (bm->cipher)
    363   {
    364   case GNUNET_CRYPTO_BSA_RSA:
    365     tlen = bm->details.rsa_blinded_message.blinded_msg_size;
    366     break;
    367   case GNUNET_CRYPTO_BSA_CS:
    368     tlen = sizeof (bm->details.cs_blinded_message);
    369     break;
    370   default:
    371     GNUNET_assert (0);
    372   }
    373   len = tlen + sizeof (be);
    374   buf = GNUNET_malloc (len);
    375   GNUNET_memcpy (buf,
    376                  &be,
    377                  sizeof (be));
    378   switch (bm->cipher)
    379   {
    380   case GNUNET_CRYPTO_BSA_RSA:
    381     GNUNET_memcpy (&buf[sizeof (be)],
    382                    bm->details.rsa_blinded_message.blinded_msg,
    383                    tlen);
    384     break;
    385   case GNUNET_CRYPTO_BSA_CS:
    386     GNUNET_memcpy (&buf[sizeof (be)],
    387                    &bm->details.cs_blinded_message,
    388                    tlen);
    389     break;
    390   default:
    391     GNUNET_assert (0);
    392   }
    393   scratch[0] = buf;
    394   param_values[0] = (void *) buf;
    395   param_lengths[0] = len;
    396   param_formats[0] = 1;
    397   return 1;
    398 }
    399 
    400 
    401 struct GNUNET_PQ_QueryParam
    402 TALER_PQ_query_param_blinded_planchet (
    403   const struct TALER_BlindedPlanchet *bp)
    404 {
    405   struct GNUNET_PQ_QueryParam res = {
    406     .conv = &qconv_blinded_planchet,
    407     .data = bp,
    408     .num_params = 1
    409   };
    410 
    411   return res;
    412 }
    413 
    414 
    415 /**
    416  * Function called to convert input argument into SQL parameters.
    417  *
    418  * @param cls closure
    419  * @param data pointer to input argument
    420  * @param data_len number of bytes in @a data (if applicable)
    421  * @param[out] param_values SQL data to set
    422  * @param[out] param_lengths SQL length data to set
    423  * @param[out] param_formats SQL format data to set
    424  * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
    425  * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
    426  * @param scratch_length number of entries left in @a scratch
    427  * @return -1 on error, number of offsets used in @a scratch otherwise
    428  */
    429 static int
    430 qconv_exchange_blinding_values (void *cls,
    431                                 const void *data,
    432                                 size_t data_len,
    433                                 void *param_values[],
    434                                 int param_lengths[],
    435                                 int param_formats[],
    436                                 unsigned int param_length,
    437                                 void *scratch[],
    438                                 unsigned int scratch_length)
    439 {
    440   const struct TALER_ExchangeBlindingValues *blinding_values = data;
    441   const struct GNUNET_CRYPTO_BlindingInputValues *bi =
    442     blinding_values->blinding_inputs;
    443   size_t tlen;
    444   size_t len;
    445   uint32_t be[2];
    446   char *buf;
    447 
    448   (void) cls;
    449   (void) data_len;
    450   GNUNET_assert (1 == param_length);
    451   GNUNET_assert (scratch_length > 0);
    452   GNUNET_break (NULL == cls);
    453   be[0] = htonl ((uint32_t) bi->cipher);
    454   be[1] = htonl (0x010000); /* magic marker: EWV */
    455   switch (bi->cipher)
    456   {
    457   case GNUNET_CRYPTO_BSA_RSA:
    458     tlen = 0;
    459     break;
    460   case GNUNET_CRYPTO_BSA_CS:
    461     tlen = sizeof (struct GNUNET_CRYPTO_CSPublicRPairP);
    462     break;
    463   default:
    464     GNUNET_assert (0);
    465   }
    466   len = tlen + sizeof (be);
    467   buf = GNUNET_malloc (len);
    468   GNUNET_memcpy (buf,
    469                  &be,
    470                  sizeof (be));
    471   switch (bi->cipher)
    472   {
    473   case GNUNET_CRYPTO_BSA_RSA:
    474     break;
    475   case GNUNET_CRYPTO_BSA_CS:
    476     GNUNET_memcpy (&buf[sizeof (be)],
    477                    &bi->details.cs_values,
    478                    tlen);
    479     break;
    480   default:
    481     GNUNET_assert (0);
    482   }
    483   scratch[0] = buf;
    484   param_values[0] = (void *) buf;
    485   param_lengths[0] = len;
    486   param_formats[0] = 1;
    487   return 1;
    488 }
    489 
    490 
    491 struct GNUNET_PQ_QueryParam
    492 TALER_PQ_query_param_exchange_blinding_values (
    493   const struct TALER_ExchangeBlindingValues *blinding_values)
    494 {
    495   struct GNUNET_PQ_QueryParam res = {
    496     .conv = &qconv_exchange_blinding_values,
    497     .data = blinding_values,
    498     .num_params = 1
    499   };
    500 
    501   return res;
    502 }
    503 
    504 
    505 /**
    506  * Function called to convert input argument into SQL parameters.
    507  *
    508  * @param cls closure
    509  * @param data pointer to input argument, here a `json_t *`
    510  * @param data_len number of bytes in @a data (if applicable)
    511  * @param[out] param_values SQL data to set
    512  * @param[out] param_lengths SQL length data to set
    513  * @param[out] param_formats SQL format data to set
    514  * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
    515  * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc()
    516  * @param scratch_length number of entries left in @a scratch
    517  * @return -1 on error, number of offsets used in @a scratch otherwise
    518  */
    519 static int
    520 qconv_json (void *cls,
    521             const void *data,
    522             size_t data_len,
    523             void *param_values[],
    524             int param_lengths[],
    525             int param_formats[],
    526             unsigned int param_length,
    527             void *scratch[],
    528             unsigned int scratch_length)
    529 {
    530   const json_t *json = data;
    531   char *str;
    532 
    533   (void) cls;
    534   (void) data_len;
    535   GNUNET_assert (1 == param_length);
    536   GNUNET_assert (scratch_length > 0);
    537   str = json_dumps (json,
    538                     JSON_COMPACT);
    539   if (NULL == str)
    540   {
    541     GNUNET_break (0);
    542     return -1;
    543   }
    544   scratch[0] = str;
    545   param_values[0] = (void *) str;
    546   param_lengths[0] = strlen (str);
    547   param_formats[0] = 1;
    548   return 1;
    549 }
    550 
    551 
    552 struct GNUNET_PQ_QueryParam
    553 TALER_PQ_query_param_json (const json_t *x)
    554 {
    555   struct GNUNET_PQ_QueryParam res = {
    556     .conv = &qconv_json,
    557     .data = x,
    558     .num_params = 1
    559   };
    560 
    561   return res;
    562 }
    563 
    564 
    565 /** ------------------- Array support  -----------------------------------**/
    566 
    567 /**
    568  * Closure for the array type handlers.
    569  *
    570  * May contain sizes information for the data, given (and handled) by the
    571  * caller.
    572  */
    573 struct qconv_array_cls
    574 {
    575   /**
    576    * If not null, contains the array of sizes (the size of the array is the
    577    * .size field in the ambient GNUNET_PQ_QueryParam struct). We do not free
    578    * this memory.
    579    *
    580    * If not null, this value has precedence over @a sizes, which MUST be NULL */
    581   const size_t *sizes;
    582 
    583   /**
    584    * If @a size and @a c_sizes are NULL, this field defines the same size
    585    * for each element in the array.
    586    */
    587   size_t same_size;
    588 
    589   /**
    590    * If true, the array parameter to the data pointer to the qconv_array is a
    591    * continuous byte array of data, either with @a same_size each or sizes
    592    * provided bytes by @a sizes;
    593    */
    594   bool continuous;
    595 
    596   /**
    597    * Type of the array elements
    598    */
    599   enum TALER_PQ_ArrayType typ;
    600 
    601   /**
    602    * Oid of the array elements
    603    */
    604   Oid oid;
    605 
    606   /**
    607    * db context, needed for OID-lookup of basis-types
    608    */
    609   struct GNUNET_PQ_Context *db;
    610 };
    611 
    612 /**
    613  * Callback to cleanup a qconv_array_cls to be used during
    614  * GNUNET_PQ_cleanup_query_params_closures
    615  */
    616 static void
    617 qconv_array_cls_cleanup (void *cls)
    618 {
    619   GNUNET_free (cls);
    620 }
    621 
    622 
    623 /**
    624  * Function called to convert input argument into SQL parameters for arrays
    625  *
    626  * Note: the format for the encoding of arrays for libpq is not very well
    627  * documented.  We peeked into various sources (postgresql and libpqtypes) for
    628  * guidance.
    629  *
    630  * @param cls Closure of type struct qconv_array_cls*
    631  * @param data Pointer to first element in the array
    632  * @param data_len Number of _elements_ in array @a data (if applicable)
    633  * @param[out] param_values SQL data to set
    634  * @param[out] param_lengths SQL length data to set
    635  * @param[out] param_formats SQL format data to set
    636  * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
    637  * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
    638  * @param scratch_length number of entries left in @a scratch
    639  * @return -1 on error, number of offsets used in @a scratch otherwise
    640  */
    641 static int
    642 qconv_array (
    643   void *cls,
    644   const void *data,
    645   size_t data_len,
    646   void *param_values[],
    647   int param_lengths[],
    648   int param_formats[],
    649   unsigned int param_length,
    650   void *scratch[],
    651   unsigned int scratch_length)
    652 {
    653   struct qconv_array_cls *meta = cls;
    654   size_t num = data_len;
    655   size_t total_size;
    656   const size_t *sizes;
    657   bool same_sized;
    658   void *elements = NULL;
    659   bool noerror = true;
    660   /* needed to capture the encoded rsa signatures */
    661   void **buffers = NULL;
    662   size_t *buffer_lengths = NULL;
    663 
    664   (void) (param_length);
    665   (void) (scratch_length);
    666 
    667   GNUNET_assert (NULL != meta);
    668   GNUNET_assert (num < INT_MAX);
    669 
    670   sizes = meta->sizes;
    671   same_sized = (0 != meta->same_size);
    672 
    673 #define RETURN_UNLESS(cond) \
    674         do { \
    675           if (! (cond)) \
    676           { \
    677             GNUNET_break ((cond)); \
    678             noerror = false; \
    679             goto DONE; \
    680           } \
    681         } while (0)
    682 
    683   /* Calculate sizes and check bounds */
    684   {
    685     /* num * length-field */
    686     size_t x = sizeof(uint32_t);
    687     size_t y = x * num;
    688     RETURN_UNLESS ((0 == num) || (y / num == x));
    689 
    690     /* size of header */
    691     total_size  = x = sizeof(struct GNUNET_PQ_ArrayHeader_P);
    692     total_size += y;
    693     RETURN_UNLESS (total_size >= x);
    694 
    695     /* sizes of elements */
    696     if (same_sized)
    697     {
    698       x = num * meta->same_size;
    699       RETURN_UNLESS ((0 == num) || (x / num == meta->same_size));
    700 
    701       y = total_size;
    702       total_size += x;
    703       RETURN_UNLESS (total_size >= y);
    704     }
    705     else  /* sizes are different per element */
    706     {
    707       switch (meta->typ)
    708       {
    709       case TALER_PQ_array_of_amount_currency:
    710         {
    711           const struct TALER_Amount *amounts = data;
    712           Oid oid_v;
    713           Oid oid_f;
    714           Oid oid_c;
    715 
    716           buffer_lengths  = GNUNET_new_array (num, size_t);
    717           /* hoist out of loop? */
    718           GNUNET_assert (GNUNET_OK ==
    719                          GNUNET_PQ_get_oid_by_name (meta->db,
    720                                                     "int8",
    721                                                     &oid_v));
    722           GNUNET_assert (GNUNET_OK ==
    723                          GNUNET_PQ_get_oid_by_name (meta->db,
    724                                                     "int4",
    725                                                     &oid_f));
    726           GNUNET_assert (GNUNET_OK ==
    727                          GNUNET_PQ_get_oid_by_name (meta->db,
    728                                                     "varchar",
    729                                                     &oid_c));
    730           for (size_t i = 0; i<num; i++)
    731           {
    732             struct TALER_PQ_AmountCurrencyP am;
    733             size_t len;
    734 
    735             len = TALER_PQ_make_taler_pq_amount_currency_ (
    736               &amounts[i],
    737               oid_v,
    738               oid_f,
    739               oid_c,
    740               &am);
    741             buffer_lengths[i] = len;
    742             y = total_size;
    743             total_size += len;
    744             RETURN_UNLESS (total_size >= y);
    745           }
    746           sizes = buffer_lengths;
    747           break;
    748         }
    749       case TALER_PQ_array_of_blinded_denom_sig:
    750         {
    751           const struct TALER_BlindedDenominationSignature *denom_sigs = data;
    752           size_t len;
    753 
    754           buffers  = GNUNET_new_array (num, void *);
    755           buffer_lengths  = GNUNET_new_array (num, size_t);
    756 
    757           for (size_t i = 0; i<num; i++)
    758           {
    759             const struct GNUNET_CRYPTO_BlindedSignature *bs =
    760               denom_sigs[i].blinded_sig;
    761 
    762             switch (bs->cipher)
    763             {
    764             case GNUNET_CRYPTO_BSA_RSA:
    765               len = GNUNET_CRYPTO_rsa_signature_encode (
    766                 bs->details.blinded_rsa_signature,
    767                 &buffers[i]);
    768               RETURN_UNLESS (len != 0);
    769               break;
    770             case GNUNET_CRYPTO_BSA_CS:
    771               len = sizeof (bs->details.blinded_cs_answer);
    772               break;
    773             default:
    774               GNUNET_assert (0);
    775             }
    776 
    777             /* for the cipher and marker */
    778             len += 2 * sizeof(uint32_t);
    779             buffer_lengths[i] = len;
    780 
    781             y = total_size;
    782             total_size += len;
    783             RETURN_UNLESS (total_size >= y);
    784           }
    785           sizes = buffer_lengths;
    786           break;
    787         }
    788       default:
    789         GNUNET_assert (0);
    790       }
    791     }
    792 
    793     RETURN_UNLESS (INT_MAX > total_size);
    794     RETURN_UNLESS (0 != total_size);
    795 
    796     elements = GNUNET_malloc (total_size);
    797   }
    798 
    799   /* Write data */
    800   {
    801     char *out = elements;
    802     struct GNUNET_PQ_ArrayHeader_P h = {
    803       .ndim = htonl (1),        /* We only support one-dimensional arrays */
    804       .has_null = htonl (0),    /* We do not support NULL entries in arrays */
    805       .lbound = htonl (1),      /* Default start index value */
    806       .dim = htonl (num),
    807       .oid = htonl (meta->oid),
    808     };
    809 
    810     /* Write header */
    811     GNUNET_memcpy (out,
    812                    &h,
    813                    sizeof(h));
    814     out += sizeof(h);
    815 
    816     /* Write elements */
    817     for (size_t i = 0; i < num; i++)
    818     {
    819       size_t sz = same_sized ? meta->same_size : sizes[i];
    820 
    821       *(uint32_t *) out = htonl (sz);
    822       out += sizeof(uint32_t);
    823       switch (meta->typ)
    824       {
    825       case TALER_PQ_array_of_amount:
    826         {
    827           const struct TALER_Amount *amounts = data;
    828           Oid oid_v;
    829           Oid oid_f;
    830 
    831           /* hoist out of loop? */
    832           GNUNET_assert (GNUNET_OK ==
    833                          GNUNET_PQ_get_oid_by_name (meta->db,
    834                                                     "int8",
    835                                                     &oid_v));
    836           GNUNET_assert (GNUNET_OK ==
    837                          GNUNET_PQ_get_oid_by_name (meta->db,
    838                                                     "int4",
    839                                                     &oid_f));
    840           {
    841             struct TALER_PQ_AmountP am
    842               = TALER_PQ_make_taler_pq_amount_ (
    843                   &amounts[i],
    844                   oid_v,
    845                   oid_f);
    846 
    847             GNUNET_memcpy (out,
    848                            &am,
    849                            sizeof(am));
    850           }
    851           break;
    852         }
    853       case TALER_PQ_array_of_amount_currency:
    854         {
    855           const struct TALER_Amount *amounts = data;
    856           Oid oid_v;
    857           Oid oid_f;
    858           Oid oid_c;
    859 
    860           /* hoist out of loop? */
    861           GNUNET_assert (GNUNET_OK ==
    862                          GNUNET_PQ_get_oid_by_name (meta->db,
    863                                                     "int8",
    864                                                     &oid_v));
    865           GNUNET_assert (GNUNET_OK ==
    866                          GNUNET_PQ_get_oid_by_name (meta->db,
    867                                                     "int4",
    868                                                     &oid_f));
    869           GNUNET_assert (GNUNET_OK ==
    870                          GNUNET_PQ_get_oid_by_name (meta->db,
    871                                                     "varchar",
    872                                                     &oid_c));
    873           {
    874             struct TALER_PQ_AmountCurrencyP am;
    875             size_t len;
    876 
    877             len = TALER_PQ_make_taler_pq_amount_currency_ (
    878               &amounts[i],
    879               oid_v,
    880               oid_f,
    881               oid_c,
    882               &am);
    883             GNUNET_memcpy (out,
    884                            &am,
    885                            len);
    886           }
    887           break;
    888         }
    889       case TALER_PQ_array_of_blinded_denom_sig:
    890         {
    891           const struct TALER_BlindedDenominationSignature *denom_sigs = data;
    892           const struct GNUNET_CRYPTO_BlindedSignature *bs =
    893             denom_sigs[i].blinded_sig;
    894           uint32_t be[2];
    895 
    896           be[0] = htonl ((uint32_t) bs->cipher);
    897           be[1] = htonl (0x01);     /* magic margker: blinded */
    898           GNUNET_memcpy (out,
    899                          &be,
    900                          sizeof(be));
    901           out += sizeof(be);
    902           sz -= sizeof(be);
    903 
    904           switch (bs->cipher)
    905           {
    906           case GNUNET_CRYPTO_BSA_RSA:
    907             /* For RSA, 'same_sized' must have been false */
    908             GNUNET_assert (NULL != buffers);
    909             GNUNET_memcpy (out,
    910                            buffers[i],
    911                            sz);
    912             break;
    913           case GNUNET_CRYPTO_BSA_CS:
    914             GNUNET_memcpy (out,
    915                            &bs->details.blinded_cs_answer,
    916                            sz);
    917             break;
    918           default:
    919             GNUNET_assert (0);
    920           }
    921           break;
    922         }
    923       case TALER_PQ_array_of_blinded_coin_hash:
    924         {
    925           const struct TALER_BlindedCoinHashP *coin_hs = data;
    926 
    927           GNUNET_memcpy (out,
    928                          &coin_hs[i],
    929                          sizeof(struct TALER_BlindedCoinHashP));
    930 
    931           break;
    932         }
    933       case TALER_PQ_array_of_denom_hash:
    934         {
    935           const struct TALER_DenominationHashP *denom_hs = data;
    936 
    937           GNUNET_memcpy (out,
    938                          &denom_hs[i],
    939                          sizeof(struct TALER_DenominationHashP));
    940           break;
    941         }
    942       case TALER_PQ_array_of_hash_code:
    943         {
    944           const struct GNUNET_HashCode *hashes = data;
    945 
    946           GNUNET_memcpy (out,
    947                          &hashes[i],
    948                          sizeof(struct GNUNET_HashCode));
    949           break;
    950         }
    951       case TALER_PQ_array_of_cs_r_pub:
    952         {
    953           const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs = data;
    954 
    955           GNUNET_memcpy (out,
    956                          &cs_r_pubs[i],
    957                          sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
    958           break;
    959         }
    960       default:
    961         {
    962           GNUNET_assert (0);
    963           break;
    964         }
    965       }
    966       out += sz;
    967     }
    968   }
    969   param_values[0] = elements;
    970   param_lengths[0] = total_size;
    971   param_formats[0] = 1;
    972   scratch[0] = elements;
    973 
    974 DONE:
    975   if (NULL != buffers)
    976   {
    977     for (size_t i = 0; i<num; i++)
    978       GNUNET_free (buffers[i]);
    979     GNUNET_free (buffers);
    980   }
    981   GNUNET_free (buffer_lengths);
    982   if (noerror)
    983     return 1;
    984   return -1;
    985 }
    986 
    987 
    988 /**
    989  * Function to generate a typ specific query parameter and corresponding closure
    990  *
    991  * @param num Number of elements in @a elements
    992  * @param continuous If true, @a elements is an continuous array of data
    993  * @param elements Array of @a num elements, either continuous or pointers
    994  * @param sizes Array of @a num sizes, one per element, may be NULL
    995  * @param same_size If not 0, all elements in @a elements have this size
    996  * @param typ Supported internal type of each element in @a elements
    997  * @param oid Oid of the type to be used in Postgres
    998  * @param[in,out] db our database handle for looking up OIDs
    999  * @return Query parameter
   1000  */
   1001 static struct GNUNET_PQ_QueryParam
   1002 query_param_array_generic (
   1003   unsigned int num,
   1004   bool continuous,
   1005   const void *elements,
   1006   const size_t *sizes,
   1007   size_t same_size,
   1008   enum TALER_PQ_ArrayType typ,
   1009   Oid oid,
   1010   struct GNUNET_PQ_Context *db)
   1011 {
   1012   struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls);
   1013 
   1014   meta->typ = typ;
   1015   meta->oid = oid;
   1016   meta->sizes = sizes;
   1017   meta->same_size = same_size;
   1018   meta->continuous = continuous;
   1019   meta->db = db;
   1020 
   1021   {
   1022     struct GNUNET_PQ_QueryParam res = {
   1023       .conv = qconv_array,
   1024       .conv_cls = meta,
   1025       .conv_cls_cleanup = qconv_array_cls_cleanup,
   1026       .data = elements,
   1027       .size = num,
   1028       .num_params = 1,
   1029     };
   1030 
   1031     return res;
   1032   }
   1033 }
   1034 
   1035 
   1036 struct GNUNET_PQ_QueryParam
   1037 TALER_PQ_query_param_array_blinded_denom_sig (
   1038   size_t num,
   1039   const struct TALER_BlindedDenominationSignature *denom_sigs,
   1040   struct GNUNET_PQ_Context *db)
   1041 {
   1042   Oid oid;
   1043 
   1044   GNUNET_assert (GNUNET_OK ==
   1045                  GNUNET_PQ_get_oid_by_name (db,
   1046                                             "bytea",
   1047                                             &oid));
   1048   return query_param_array_generic (num,
   1049                                     true,
   1050                                     denom_sigs,
   1051                                     NULL,
   1052                                     0,
   1053                                     TALER_PQ_array_of_blinded_denom_sig,
   1054                                     oid,
   1055                                     NULL);
   1056 }
   1057 
   1058 
   1059 struct GNUNET_PQ_QueryParam
   1060 TALER_PQ_query_param_array_blinded_coin_hash (
   1061   size_t num,
   1062   const struct TALER_BlindedCoinHashP *coin_hs,
   1063   struct GNUNET_PQ_Context *db)
   1064 {
   1065   Oid oid;
   1066 
   1067   GNUNET_assert (GNUNET_OK ==
   1068                  GNUNET_PQ_get_oid_by_name (db,
   1069                                             "bytea",
   1070                                             &oid));
   1071   return query_param_array_generic (num,
   1072                                     true,
   1073                                     coin_hs,
   1074                                     NULL,
   1075                                     sizeof(struct TALER_BlindedCoinHashP),
   1076                                     TALER_PQ_array_of_blinded_coin_hash,
   1077                                     oid,
   1078                                     NULL);
   1079 }
   1080 
   1081 
   1082 struct GNUNET_PQ_QueryParam
   1083 TALER_PQ_query_param_array_denom_hash (
   1084   size_t num,
   1085   const struct TALER_DenominationHashP *denom_hs,
   1086   struct GNUNET_PQ_Context *db)
   1087 {
   1088   Oid oid;
   1089 
   1090   GNUNET_assert (GNUNET_OK ==
   1091                  GNUNET_PQ_get_oid_by_name (db,
   1092                                             "bytea",
   1093                                             &oid));
   1094   return query_param_array_generic (num,
   1095                                     true,
   1096                                     denom_hs,
   1097                                     NULL,
   1098                                     sizeof(struct TALER_DenominationHashP),
   1099                                     TALER_PQ_array_of_denom_hash,
   1100                                     oid,
   1101                                     NULL);
   1102 }
   1103 
   1104 
   1105 struct GNUNET_PQ_QueryParam
   1106 TALER_PQ_query_param_array_hash_code (
   1107   size_t num,
   1108   const struct GNUNET_HashCode *hashes,
   1109   struct GNUNET_PQ_Context *db)
   1110 {
   1111   Oid oid;
   1112   GNUNET_assert (GNUNET_OK ==
   1113                  GNUNET_PQ_get_oid_by_name (db, "gnunet_hashcode", &oid));
   1114   return query_param_array_generic (num,
   1115                                     true,
   1116                                     hashes,
   1117                                     NULL,
   1118                                     sizeof(struct GNUNET_HashCode),
   1119                                     TALER_PQ_array_of_hash_code,
   1120                                     oid,
   1121                                     NULL);
   1122 }
   1123 
   1124 
   1125 struct GNUNET_PQ_QueryParam
   1126 TALER_PQ_query_param_array_amount (
   1127   size_t num,
   1128   const struct TALER_Amount *amounts,
   1129   struct GNUNET_PQ_Context *db)
   1130 {
   1131   Oid oid;
   1132 
   1133   GNUNET_assert (GNUNET_OK ==
   1134                  GNUNET_PQ_get_oid_by_name (db,
   1135                                             "taler_amount",
   1136                                             &oid));
   1137   return query_param_array_generic (
   1138     num,
   1139     true,
   1140     amounts,
   1141     NULL,
   1142     sizeof(struct TALER_PQ_AmountP),
   1143     TALER_PQ_array_of_amount,
   1144     oid,
   1145     db);
   1146 }
   1147 
   1148 
   1149 struct GNUNET_PQ_QueryParam
   1150 TALER_PQ_query_param_array_amount_with_currency (
   1151   size_t num,
   1152   const struct TALER_Amount *amounts,
   1153   struct GNUNET_PQ_Context *db)
   1154 {
   1155   Oid oid;
   1156 
   1157   GNUNET_assert (GNUNET_OK ==
   1158                  GNUNET_PQ_get_oid_by_name (db,
   1159                                             "taler_amount_currency",
   1160                                             &oid));
   1161   return query_param_array_generic (
   1162     num,
   1163     true,
   1164     amounts,
   1165     NULL,
   1166     0, /* currency is technically variable length */
   1167     TALER_PQ_array_of_amount_currency,
   1168     oid,
   1169     db);
   1170 }
   1171 
   1172 
   1173 struct GNUNET_PQ_QueryParam
   1174 TALER_PQ_query_param_array_cs_r_pub (
   1175   size_t num,
   1176   const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs,
   1177   struct GNUNET_PQ_Context *db)
   1178 {
   1179   Oid oid;
   1180 
   1181   GNUNET_assert (GNUNET_OK ==
   1182                  GNUNET_PQ_get_oid_by_name (db,
   1183                                             "bytea",
   1184                                             &oid));
   1185   return query_param_array_generic (
   1186     num,
   1187     true,
   1188     cs_r_pubs,
   1189     NULL,
   1190     sizeof(struct GNUNET_CRYPTO_CSPublicRPairP),
   1191     TALER_PQ_array_of_cs_r_pub,
   1192     oid,
   1193     db);
   1194 }
   1195 
   1196 
   1197 /* end of pq/pq_query_helper.c */