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


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