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


      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 functions to initialize parameter arrays
     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_static_assert (sizeof(uint32_t) == sizeof(Oid));
     60   GNUNET_assert (NULL != db);
     61   GNUNET_assert (NULL != amount);
     62   GNUNET_assert (1 == param_length);
     63   GNUNET_assert (1 <= scratch_length);
     64   GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
     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_static_assert (sizeof(uint32_t) == sizeof(Oid));
    151   GNUNET_assert (NULL != db);
    152   GNUNET_assert (NULL != amount);
    153   GNUNET_assert (1 == param_length);
    154   GNUNET_assert (1 <= scratch_length);
    155   GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
    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       case TALER_PQ_array_of_denom_sig:
    789         {
    790           const struct TALER_DenominationSignature *denom_sigs = data;
    791           size_t len;
    792 
    793           buffers  = GNUNET_new_array (num, void *);
    794           buffer_lengths  = GNUNET_new_array (num, size_t);
    795 
    796           for (size_t i = 0; i<num; i++)
    797           {
    798             const struct GNUNET_CRYPTO_UnblindedSignature *ubs =
    799               denom_sigs[i].unblinded_sig;
    800 
    801             switch (ubs->cipher)
    802             {
    803             case GNUNET_CRYPTO_BSA_RSA:
    804               len = GNUNET_CRYPTO_rsa_signature_encode (
    805                 ubs->details.rsa_signature,
    806                 &buffers[i]);
    807               RETURN_UNLESS (len != 0);
    808               break;
    809             case GNUNET_CRYPTO_BSA_CS:
    810               len = sizeof (ubs->details.cs_signature);
    811               break;
    812             default:
    813               GNUNET_assert (0);
    814             }
    815 
    816             /* for the cipher and marker */
    817             len += 2 * sizeof(uint32_t);
    818             buffer_lengths[i] = len;
    819 
    820             y = total_size;
    821             total_size += len;
    822             RETURN_UNLESS (total_size >= y);
    823           }
    824           sizes = buffer_lengths;
    825           break;
    826         }
    827       default:
    828         GNUNET_assert (0);
    829       }
    830     }
    831 
    832     RETURN_UNLESS (INT_MAX > total_size);
    833     RETURN_UNLESS (0 != total_size);
    834 
    835     elements = GNUNET_malloc (total_size);
    836   }
    837 
    838   /* Write data */
    839   {
    840     char *out = elements;
    841     struct GNUNET_PQ_ArrayHeader_P h = {
    842       .ndim = htonl (1),        /* We only support one-dimensional arrays */
    843       .has_null = htonl (0),    /* We do not support NULL entries in arrays */
    844       .lbound = htonl (1),      /* Default start index value */
    845       .dim = htonl (num),
    846       .oid = htonl (meta->oid),
    847     };
    848 
    849     /* Write header */
    850     GNUNET_memcpy (out,
    851                    &h,
    852                    sizeof(h));
    853     out += sizeof(h);
    854 
    855     /* Write elements */
    856     for (size_t i = 0; i < num; i++)
    857     {
    858       size_t sz = same_sized ? meta->same_size : sizes[i];
    859       uint32_t bsz = htonl ((uint32_t) sz);
    860 
    861       /* Note: @a out is not necessarily aligned, as elements
    862          may have odd sizes; so we must not type-pun here. */
    863       GNUNET_memcpy (out,
    864                      &bsz,
    865                      sizeof (bsz));
    866       out += sizeof(uint32_t);
    867       switch (meta->typ)
    868       {
    869       case TALER_PQ_array_of_amount:
    870         {
    871           const struct TALER_Amount *amounts = data;
    872           Oid oid_v;
    873           Oid oid_f;
    874 
    875           /* hoist out of loop? */
    876           GNUNET_assert (GNUNET_OK ==
    877                          GNUNET_PQ_get_oid_by_name (meta->db,
    878                                                     "int8",
    879                                                     &oid_v));
    880           GNUNET_assert (GNUNET_OK ==
    881                          GNUNET_PQ_get_oid_by_name (meta->db,
    882                                                     "int4",
    883                                                     &oid_f));
    884           {
    885             struct TALER_PQ_AmountP am
    886               = TALER_PQ_make_taler_pq_amount_ (
    887                   &amounts[i],
    888                   oid_v,
    889                   oid_f);
    890 
    891             GNUNET_memcpy (out,
    892                            &am,
    893                            sizeof(am));
    894           }
    895           break;
    896         }
    897       case TALER_PQ_array_of_amount_currency:
    898         {
    899           const struct TALER_Amount *amounts = data;
    900           Oid oid_v;
    901           Oid oid_f;
    902           Oid oid_c;
    903 
    904           /* hoist out of loop? */
    905           GNUNET_assert (GNUNET_OK ==
    906                          GNUNET_PQ_get_oid_by_name (meta->db,
    907                                                     "int8",
    908                                                     &oid_v));
    909           GNUNET_assert (GNUNET_OK ==
    910                          GNUNET_PQ_get_oid_by_name (meta->db,
    911                                                     "int4",
    912                                                     &oid_f));
    913           GNUNET_assert (GNUNET_OK ==
    914                          GNUNET_PQ_get_oid_by_name (meta->db,
    915                                                     "varchar",
    916                                                     &oid_c));
    917           {
    918             struct TALER_PQ_AmountCurrencyP am;
    919             size_t len;
    920 
    921             len = TALER_PQ_make_taler_pq_amount_currency_ (
    922               &amounts[i],
    923               oid_v,
    924               oid_f,
    925               oid_c,
    926               &am);
    927             GNUNET_memcpy (out,
    928                            &am,
    929                            len);
    930           }
    931           break;
    932         }
    933       case TALER_PQ_array_of_blinded_denom_sig:
    934         {
    935           const struct TALER_BlindedDenominationSignature *denom_sigs = data;
    936           const struct GNUNET_CRYPTO_BlindedSignature *bs =
    937             denom_sigs[i].blinded_sig;
    938           uint32_t be[2];
    939 
    940           be[0] = htonl ((uint32_t) bs->cipher);
    941           be[1] = htonl (0x01);     /* magic margker: blinded */
    942           GNUNET_memcpy (out,
    943                          &be,
    944                          sizeof(be));
    945           out += sizeof(be);
    946           sz -= sizeof(be);
    947 
    948           switch (bs->cipher)
    949           {
    950           case GNUNET_CRYPTO_BSA_RSA:
    951             /* For RSA, 'same_sized' must have been false */
    952             GNUNET_assert (NULL != buffers);
    953             GNUNET_memcpy (out,
    954                            buffers[i],
    955                            sz);
    956             break;
    957           case GNUNET_CRYPTO_BSA_CS:
    958             GNUNET_memcpy (out,
    959                            &bs->details.blinded_cs_answer,
    960                            sz);
    961             break;
    962           default:
    963             GNUNET_assert (0);
    964           }
    965           break;
    966         }
    967       case TALER_PQ_array_of_denom_sig:
    968         {
    969           const struct TALER_DenominationSignature *denom_sigs = data;
    970           const struct GNUNET_CRYPTO_UnblindedSignature *ubs =
    971             denom_sigs[i].unblinded_sig;
    972           uint32_t be[2];
    973 
    974           /* Same encoding as GNUNET_PQ_query_param_unblinded_sig() */
    975           be[0] = htonl ((uint32_t) ubs->cipher);
    976           be[1] = htonl (0x00);     /* magic marker: unblinded */
    977           GNUNET_memcpy (out,
    978                          &be,
    979                          sizeof(be));
    980           out += sizeof(be);
    981           sz -= sizeof(be);
    982 
    983           switch (ubs->cipher)
    984           {
    985           case GNUNET_CRYPTO_BSA_RSA:
    986             /* For RSA, 'same_sized' must have been false */
    987             GNUNET_assert (NULL != buffers);
    988             GNUNET_memcpy (out,
    989                            buffers[i],
    990                            sz);
    991             break;
    992           case GNUNET_CRYPTO_BSA_CS:
    993             GNUNET_memcpy (out,
    994                            &ubs->details.cs_signature,
    995                            sz);
    996             break;
    997           default:
    998             GNUNET_assert (0);
    999           }
   1000           break;
   1001         }
   1002       case TALER_PQ_array_of_blinded_coin_hash:
   1003         {
   1004           const struct TALER_BlindedCoinHashP *coin_hs = data;
   1005 
   1006           GNUNET_memcpy (out,
   1007                          &coin_hs[i],
   1008                          sizeof(struct TALER_BlindedCoinHashP));
   1009 
   1010           break;
   1011         }
   1012       case TALER_PQ_array_of_denom_hash:
   1013         {
   1014           const struct TALER_DenominationHashP *denom_hs = data;
   1015 
   1016           GNUNET_memcpy (out,
   1017                          &denom_hs[i],
   1018                          sizeof(struct TALER_DenominationHashP));
   1019           break;
   1020         }
   1021       case TALER_PQ_array_of_hash_code:
   1022         {
   1023           const struct GNUNET_HashCode *hashes = data;
   1024 
   1025           GNUNET_memcpy (out,
   1026                          &hashes[i],
   1027                          sizeof(struct GNUNET_HashCode));
   1028           break;
   1029         }
   1030       case TALER_PQ_array_of_cs_r_pub:
   1031         {
   1032           const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs = data;
   1033 
   1034           GNUNET_memcpy (out,
   1035                          &cs_r_pubs[i],
   1036                          sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
   1037           break;
   1038         }
   1039       default:
   1040         {
   1041           GNUNET_assert (0);
   1042           break;
   1043         }
   1044       }
   1045       out += sz;
   1046     }
   1047   }
   1048   param_values[0] = elements;
   1049   param_lengths[0] = total_size;
   1050   param_formats[0] = 1;
   1051   scratch[0] = elements;
   1052 
   1053 DONE:
   1054   if (NULL != buffers)
   1055   {
   1056     for (size_t i = 0; i<num; i++)
   1057       GNUNET_free (buffers[i]);
   1058     GNUNET_free (buffers);
   1059   }
   1060   GNUNET_free (buffer_lengths);
   1061   if (noerror)
   1062     return 1;
   1063   return -1;
   1064 }
   1065 
   1066 
   1067 /**
   1068  * Function to generate a typ specific query parameter and corresponding closure
   1069  *
   1070  * @param num Number of elements in @a elements
   1071  * @param continuous If true, @a elements is an continuous array of data
   1072  * @param elements Array of @a num elements, either continuous or pointers
   1073  * @param sizes Array of @a num sizes, one per element, may be NULL
   1074  * @param same_size If not 0, all elements in @a elements have this size
   1075  * @param typ Supported internal type of each element in @a elements
   1076  * @param oid Oid of the type to be used in Postgres
   1077  * @param[in,out] db our database handle for looking up OIDs
   1078  * @return Query parameter
   1079  */
   1080 static struct GNUNET_PQ_QueryParam
   1081 query_param_array_generic (
   1082   unsigned int num,
   1083   bool continuous,
   1084   const void *elements,
   1085   const size_t *sizes,
   1086   size_t same_size,
   1087   enum TALER_PQ_ArrayType typ,
   1088   Oid oid,
   1089   struct GNUNET_PQ_Context *db)
   1090 {
   1091   struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls);
   1092 
   1093   meta->typ = typ;
   1094   meta->oid = oid;
   1095   meta->sizes = sizes;
   1096   meta->same_size = same_size;
   1097   meta->continuous = continuous;
   1098   meta->db = db;
   1099 
   1100   {
   1101     struct GNUNET_PQ_QueryParam res = {
   1102       .conv = qconv_array,
   1103       .conv_cls = meta,
   1104       .conv_cls_cleanup = qconv_array_cls_cleanup,
   1105       .data = elements,
   1106       .size = num,
   1107       .num_params = 1,
   1108     };
   1109 
   1110     return res;
   1111   }
   1112 }
   1113 
   1114 
   1115 struct GNUNET_PQ_QueryParam
   1116 TALER_PQ_query_param_array_blinded_denom_sig (
   1117   size_t num,
   1118   const struct TALER_BlindedDenominationSignature *denom_sigs,
   1119   struct GNUNET_PQ_Context *db)
   1120 {
   1121   Oid oid;
   1122 
   1123   GNUNET_assert (GNUNET_OK ==
   1124                  GNUNET_PQ_get_oid_by_name (db,
   1125                                             "bytea",
   1126                                             &oid));
   1127   return query_param_array_generic (num,
   1128                                     true,
   1129                                     denom_sigs,
   1130                                     NULL,
   1131                                     0,
   1132                                     TALER_PQ_array_of_blinded_denom_sig,
   1133                                     oid,
   1134                                     NULL);
   1135 }
   1136 
   1137 
   1138 struct GNUNET_PQ_QueryParam
   1139 TALER_PQ_query_param_array_denom_sig (
   1140   size_t num,
   1141   const struct TALER_DenominationSignature *denom_sigs,
   1142   struct GNUNET_PQ_Context *db)
   1143 {
   1144   Oid oid;
   1145 
   1146   GNUNET_assert (GNUNET_OK ==
   1147                  GNUNET_PQ_get_oid_by_name (db,
   1148                                             "bytea",
   1149                                             &oid));
   1150   return query_param_array_generic (num,
   1151                                     true,
   1152                                     denom_sigs,
   1153                                     NULL,
   1154                                     0,
   1155                                     TALER_PQ_array_of_denom_sig,
   1156                                     oid,
   1157                                     NULL);
   1158 }
   1159 
   1160 
   1161 struct GNUNET_PQ_QueryParam
   1162 TALER_PQ_query_param_array_blinded_coin_hash (
   1163   size_t num,
   1164   const struct TALER_BlindedCoinHashP *coin_hs,
   1165   struct GNUNET_PQ_Context *db)
   1166 {
   1167   Oid oid;
   1168 
   1169   GNUNET_assert (GNUNET_OK ==
   1170                  GNUNET_PQ_get_oid_by_name (db,
   1171                                             "bytea",
   1172                                             &oid));
   1173   return query_param_array_generic (num,
   1174                                     true,
   1175                                     coin_hs,
   1176                                     NULL,
   1177                                     sizeof(struct TALER_BlindedCoinHashP),
   1178                                     TALER_PQ_array_of_blinded_coin_hash,
   1179                                     oid,
   1180                                     NULL);
   1181 }
   1182 
   1183 
   1184 struct GNUNET_PQ_QueryParam
   1185 TALER_PQ_query_param_array_denom_hash (
   1186   size_t num,
   1187   const struct TALER_DenominationHashP *denom_hs,
   1188   struct GNUNET_PQ_Context *db)
   1189 {
   1190   Oid oid;
   1191 
   1192   GNUNET_assert (GNUNET_OK ==
   1193                  GNUNET_PQ_get_oid_by_name (db,
   1194                                             "bytea",
   1195                                             &oid));
   1196   return query_param_array_generic (num,
   1197                                     true,
   1198                                     denom_hs,
   1199                                     NULL,
   1200                                     sizeof(struct TALER_DenominationHashP),
   1201                                     TALER_PQ_array_of_denom_hash,
   1202                                     oid,
   1203                                     NULL);
   1204 }
   1205 
   1206 
   1207 struct GNUNET_PQ_QueryParam
   1208 TALER_PQ_query_param_array_hash_code (
   1209   size_t num,
   1210   const struct GNUNET_HashCode *hashes,
   1211   struct GNUNET_PQ_Context *db)
   1212 {
   1213   Oid oid;
   1214   GNUNET_assert (GNUNET_OK ==
   1215                  GNUNET_PQ_get_oid_by_name (db, "gnunet_hashcode", &oid));
   1216   return query_param_array_generic (num,
   1217                                     true,
   1218                                     hashes,
   1219                                     NULL,
   1220                                     sizeof(struct GNUNET_HashCode),
   1221                                     TALER_PQ_array_of_hash_code,
   1222                                     oid,
   1223                                     NULL);
   1224 }
   1225 
   1226 
   1227 struct GNUNET_PQ_QueryParam
   1228 TALER_PQ_query_param_array_amount (
   1229   size_t num,
   1230   const struct TALER_Amount *amounts,
   1231   struct GNUNET_PQ_Context *db)
   1232 {
   1233   Oid oid;
   1234 
   1235   GNUNET_assert (GNUNET_OK ==
   1236                  GNUNET_PQ_get_oid_by_name (db,
   1237                                             "taler_amount",
   1238                                             &oid));
   1239   return query_param_array_generic (
   1240     num,
   1241     true,
   1242     amounts,
   1243     NULL,
   1244     sizeof(struct TALER_PQ_AmountP),
   1245     TALER_PQ_array_of_amount,
   1246     oid,
   1247     db);
   1248 }
   1249 
   1250 
   1251 struct GNUNET_PQ_QueryParam
   1252 TALER_PQ_query_param_array_amount_with_currency (
   1253   size_t num,
   1254   const struct TALER_Amount *amounts,
   1255   const char *schema,
   1256   struct GNUNET_PQ_Context *db)
   1257 {
   1258   Oid oid;
   1259   char *tn;
   1260 
   1261   if (NULL != schema)
   1262     GNUNET_asprintf (&tn,
   1263                      "%s.taler_amount_currency",
   1264                      schema);
   1265   else
   1266     GNUNET_asprintf (&tn,
   1267                      "taler_amount_currency");
   1268   GNUNET_assert (GNUNET_OK ==
   1269                  GNUNET_PQ_get_oid_by_name (db,
   1270                                             tn,
   1271                                             &oid));
   1272   GNUNET_free (tn);
   1273   return query_param_array_generic (
   1274     num,
   1275     true,
   1276     amounts,
   1277     NULL,
   1278     0, /* currency is technically variable length */
   1279     TALER_PQ_array_of_amount_currency,
   1280     oid,
   1281     db);
   1282 }
   1283 
   1284 
   1285 struct GNUNET_PQ_QueryParam
   1286 TALER_PQ_query_param_array_cs_r_pub (
   1287   size_t num,
   1288   const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs,
   1289   struct GNUNET_PQ_Context *db)
   1290 {
   1291   Oid oid;
   1292 
   1293   GNUNET_assert (GNUNET_OK ==
   1294                  GNUNET_PQ_get_oid_by_name (db,
   1295                                             "bytea",
   1296                                             &oid));
   1297   return query_param_array_generic (
   1298     num,
   1299     true,
   1300     cs_r_pubs,
   1301     NULL,
   1302     sizeof(struct GNUNET_CRYPTO_CSPublicRPairP),
   1303     TALER_PQ_array_of_cs_r_pub,
   1304     oid,
   1305     db);
   1306 }
   1307 
   1308 
   1309 /* end of pq/pq_query_helper.c */