LCOV - code coverage report
Current view: top level - pq - pq_query_helper.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 71.3 % 363 259
Test Date: 2026-04-14 15:39:31 Functions: 70.8 % 24 17

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2014-2023 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU General Public License as published by the Free Software
       7              :   Foundation; either version 3, or (at your option) any later version.
       8              : 
       9              :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10              :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11              :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU General Public License along with
      14              :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              : */
      16              : /**
      17              :  * @file pq/pq_query_helper.c
      18              :  * @brief helper functions for Taler-specific libpq (PostGres) interactions
      19              :  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
      20              :  * @author Florian Dold
      21              :  * @author Christian Grothoff
      22              :  */
      23              : #include <gnunet/gnunet_common.h>
      24              : #include <gnunet/gnunet_util_lib.h>
      25              : #include <gnunet/gnunet_pq_lib.h>
      26              : #include "taler/taler_pq_lib.h"
      27              : #include "pq_common.h"
      28              : 
      29              : 
      30              : /**
      31              :  * Function called to convert input amount into SQL parameter as tuple.
      32              :  *
      33              :  * @param cls closure
      34              :  * @param data pointer to input argument, here a `struct TALER_Amount`
      35              :  * @param data_len number of bytes in @a data (if applicable)
      36              :  * @param[out] param_values SQL data to set
      37              :  * @param[out] param_lengths SQL length data to set
      38              :  * @param[out] param_formats SQL format data to set
      39              :  * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
      40              :  * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc()
      41              :  * @param scratch_length number of entries left in @a scratch
      42              :  * @return -1 on error, number of offsets used in @a scratch otherwise
      43              :  */
      44              : static int
      45            1 : 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            1 :   struct GNUNET_PQ_Context *db = cls;
      56            1 :   const struct TALER_Amount *amount = data;
      57              :   size_t sz;
      58              : 
      59            1 :   GNUNET_assert (NULL != db);
      60            1 :   GNUNET_assert (NULL != amount);
      61            1 :   GNUNET_assert (1 == param_length);
      62            1 :   GNUNET_assert (1 <= scratch_length);
      63            1 :   GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
      64              :   GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid));
      65              :   {
      66              :     char *out;
      67              :     Oid oid_v;
      68              :     Oid oid_f;
      69              :     Oid oid_c;
      70              :     struct TALER_PQ_AmountCurrencyP d;
      71              : 
      72            1 :     GNUNET_assert (GNUNET_OK ==
      73              :                    GNUNET_PQ_get_oid_by_name (db,
      74              :                                               "int8",
      75              :                                               &oid_v));
      76            1 :     GNUNET_assert (GNUNET_OK ==
      77              :                    GNUNET_PQ_get_oid_by_name (db,
      78              :                                               "int4",
      79              :                                               &oid_f));
      80            1 :     GNUNET_assert (GNUNET_OK ==
      81              :                    GNUNET_PQ_get_oid_by_name (db,
      82              :                                               "varchar",
      83              :                                               &oid_c));
      84            1 :     sz = TALER_PQ_make_taler_pq_amount_currency_ (amount,
      85              :                                                   oid_v,
      86              :                                                   oid_f,
      87              :                                                   oid_c,
      88              :                                                   &d);
      89            1 :     out = GNUNET_malloc (sz);
      90            1 :     memcpy (out,
      91              :             &d,
      92              :             sz);
      93            1 :     scratch[0] = out;
      94              :   }
      95              : 
      96            1 :   param_values[0] = scratch[0];
      97            1 :   param_lengths[0] = sz;
      98            1 :   param_formats[0] = 1;
      99              : 
     100            1 :   return 1;
     101              : }
     102              : 
     103              : 
     104              : struct GNUNET_PQ_QueryParam
     105            1 : TALER_PQ_query_param_amount_with_currency (
     106              :   const struct GNUNET_PQ_Context *db,
     107              :   const struct TALER_Amount *amount)
     108              : {
     109            1 :   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            1 :   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         3272 : 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         3272 :   struct GNUNET_PQ_Context *db = cls;
     147         3272 :   const struct TALER_Amount *amount = data;
     148              :   size_t sz;
     149              : 
     150         3272 :   GNUNET_assert (NULL != db);
     151         3272 :   GNUNET_assert (NULL != amount);
     152         3272 :   GNUNET_assert (1 == param_length);
     153         3272 :   GNUNET_assert (1 <= scratch_length);
     154         3272 :   GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
     155              :   GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid));
     156              :   {
     157              :     char *out;
     158              :     Oid oid_v;
     159              :     Oid oid_f;
     160              : 
     161         3272 :     GNUNET_assert (GNUNET_OK ==
     162              :                    GNUNET_PQ_get_oid_by_name (db,
     163              :                                               "int8",
     164              :                                               &oid_v));
     165         3272 :     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         3272 :         = TALER_PQ_make_taler_pq_amount_ (amount,
     173              :                                           oid_v,
     174              :                                           oid_f);
     175              : 
     176         3272 :       sz = sizeof(d);
     177         3272 :       out = GNUNET_malloc (sz);
     178         3272 :       scratch[0] = out;
     179         3272 :       GNUNET_memcpy (out,
     180              :                      &d,
     181              :                      sizeof(d));
     182              :     }
     183              :   }
     184              : 
     185         3272 :   param_values[0] = scratch[0];
     186         3272 :   param_lengths[0] = sz;
     187         3272 :   param_formats[0] = 1;
     188              : 
     189         3272 :   return 1;
     190              : }
     191              : 
     192              : 
     193              : struct GNUNET_PQ_QueryParam
     194         3272 : TALER_PQ_query_param_amount (
     195              :   const struct GNUNET_PQ_Context *db,
     196              :   const struct TALER_Amount *amount)
     197              : {
     198         3272 :   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         3272 :   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          493 : 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          493 :   const struct TALER_DenominationPublicKey *denom_pub = data;
     236          493 :   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          493 :   GNUNET_assert (1 == param_length);
     246          493 :   GNUNET_assert (scratch_length > 0);
     247          493 :   GNUNET_break (NULL == cls);
     248          493 :   be[0] = htonl ((uint32_t) bsp->cipher);
     249          493 :   be[1] = htonl (denom_pub->age_mask.bits);
     250          493 :   switch (bsp->cipher)
     251              :   {
     252          282 :   case GNUNET_CRYPTO_BSA_RSA:
     253          282 :     tlen = GNUNET_CRYPTO_rsa_public_key_encode (
     254          282 :       bsp->details.rsa_public_key,
     255              :       &tbuf);
     256          282 :     break;
     257          211 :   case GNUNET_CRYPTO_BSA_CS:
     258          211 :     tlen = sizeof (bsp->details.cs_public_key);
     259          211 :     break;
     260            0 :   default:
     261            0 :     GNUNET_assert (0);
     262              :   }
     263          493 :   len = tlen + sizeof (be);
     264          493 :   buf = GNUNET_malloc (len);
     265          493 :   GNUNET_memcpy (buf,
     266              :                  be,
     267              :                  sizeof (be));
     268          493 :   switch (bsp->cipher)
     269              :   {
     270          282 :   case GNUNET_CRYPTO_BSA_RSA:
     271          282 :     GNUNET_memcpy (&buf[sizeof (be)],
     272              :                    tbuf,
     273              :                    tlen);
     274          282 :     GNUNET_free (tbuf);
     275          282 :     break;
     276          211 :   case GNUNET_CRYPTO_BSA_CS:
     277          211 :     GNUNET_memcpy (&buf[sizeof (be)],
     278              :                    &bsp->details.cs_public_key,
     279              :                    tlen);
     280          211 :     break;
     281            0 :   default:
     282            0 :     GNUNET_assert (0);
     283              :   }
     284              : 
     285          493 :   scratch[0] = buf;
     286          493 :   param_values[0] = (void *) buf;
     287          493 :   param_lengths[0] = len;
     288          493 :   param_formats[0] = 1;
     289          493 :   return 1;
     290              : }
     291              : 
     292              : 
     293              : struct GNUNET_PQ_QueryParam
     294          493 : TALER_PQ_query_param_denom_pub (
     295              :   const struct TALER_DenominationPublicKey *denom_pub)
     296              : {
     297          493 :   struct GNUNET_PQ_QueryParam res = {
     298              :     .conv = &qconv_denom_pub,
     299              :     .data = denom_pub,
     300              :     .num_params = 1
     301              :   };
     302              : 
     303          493 :   return res;
     304              : }
     305              : 
     306              : 
     307              : struct GNUNET_PQ_QueryParam
     308          169 : TALER_PQ_query_param_denom_sig (
     309              :   const struct TALER_DenominationSignature *denom_sig)
     310              : {
     311          169 :   return GNUNET_PQ_query_param_unblinded_sig (denom_sig->unblinded_sig);
     312              : }
     313              : 
     314              : 
     315              : struct GNUNET_PQ_QueryParam
     316            0 : TALER_PQ_query_param_blinded_denom_sig (
     317              :   const struct TALER_BlindedDenominationSignature *denom_sig)
     318              : {
     319            0 :   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            0 : 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            0 :   const struct TALER_BlindedPlanchet *bp = data;
     349            0 :   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            0 :   GNUNET_assert (1 == param_length);
     358            0 :   GNUNET_assert (scratch_length > 0);
     359            0 :   GNUNET_break (NULL == cls);
     360            0 :   be[0] = htonl ((uint32_t) bm->cipher);
     361            0 :   be[1] = htonl (0x0100); /* magic marker: blinded */
     362            0 :   switch (bm->cipher)
     363              :   {
     364            0 :   case GNUNET_CRYPTO_BSA_RSA:
     365            0 :     tlen = bm->details.rsa_blinded_message.blinded_msg_size;
     366            0 :     break;
     367            0 :   case GNUNET_CRYPTO_BSA_CS:
     368            0 :     tlen = sizeof (bm->details.cs_blinded_message);
     369            0 :     break;
     370            0 :   default:
     371            0 :     GNUNET_assert (0);
     372              :   }
     373            0 :   len = tlen + sizeof (be);
     374            0 :   buf = GNUNET_malloc (len);
     375            0 :   GNUNET_memcpy (buf,
     376              :                  &be,
     377              :                  sizeof (be));
     378            0 :   switch (bm->cipher)
     379              :   {
     380            0 :   case GNUNET_CRYPTO_BSA_RSA:
     381            0 :     GNUNET_memcpy (&buf[sizeof (be)],
     382              :                    bm->details.rsa_blinded_message.blinded_msg,
     383              :                    tlen);
     384            0 :     break;
     385            0 :   case GNUNET_CRYPTO_BSA_CS:
     386            0 :     GNUNET_memcpy (&buf[sizeof (be)],
     387              :                    &bm->details.cs_blinded_message,
     388              :                    tlen);
     389            0 :     break;
     390            0 :   default:
     391            0 :     GNUNET_assert (0);
     392              :   }
     393            0 :   scratch[0] = buf;
     394            0 :   param_values[0] = (void *) buf;
     395            0 :   param_lengths[0] = len;
     396            0 :   param_formats[0] = 1;
     397            0 :   return 1;
     398              : }
     399              : 
     400              : 
     401              : struct GNUNET_PQ_QueryParam
     402            0 : TALER_PQ_query_param_blinded_planchet (
     403              :   const struct TALER_BlindedPlanchet *bp)
     404              : {
     405            0 :   struct GNUNET_PQ_QueryParam res = {
     406              :     .conv = &qconv_blinded_planchet,
     407              :     .data = bp,
     408              :     .num_params = 1
     409              :   };
     410              : 
     411            0 :   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            0 : 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            0 :   const struct TALER_ExchangeBlindingValues *blinding_values = data;
     441            0 :   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            0 :   GNUNET_assert (1 == param_length);
     451            0 :   GNUNET_assert (scratch_length > 0);
     452            0 :   GNUNET_break (NULL == cls);
     453            0 :   be[0] = htonl ((uint32_t) bi->cipher);
     454            0 :   be[1] = htonl (0x010000); /* magic marker: EWV */
     455            0 :   switch (bi->cipher)
     456              :   {
     457            0 :   case GNUNET_CRYPTO_BSA_RSA:
     458            0 :     tlen = 0;
     459            0 :     break;
     460            0 :   case GNUNET_CRYPTO_BSA_CS:
     461            0 :     tlen = sizeof (struct GNUNET_CRYPTO_CSPublicRPairP);
     462            0 :     break;
     463            0 :   default:
     464            0 :     GNUNET_assert (0);
     465              :   }
     466            0 :   len = tlen + sizeof (be);
     467            0 :   buf = GNUNET_malloc (len);
     468            0 :   GNUNET_memcpy (buf,
     469              :                  &be,
     470              :                  sizeof (be));
     471            0 :   switch (bi->cipher)
     472              :   {
     473            0 :   case GNUNET_CRYPTO_BSA_RSA:
     474            0 :     break;
     475            0 :   case GNUNET_CRYPTO_BSA_CS:
     476            0 :     GNUNET_memcpy (&buf[sizeof (be)],
     477              :                    &bi->details.cs_values,
     478              :                    tlen);
     479            0 :     break;
     480            0 :   default:
     481            0 :     GNUNET_assert (0);
     482              :   }
     483            0 :   scratch[0] = buf;
     484            0 :   param_values[0] = (void *) buf;
     485            0 :   param_lengths[0] = len;
     486            0 :   param_formats[0] = 1;
     487            0 :   return 1;
     488              : }
     489              : 
     490              : 
     491              : struct GNUNET_PQ_QueryParam
     492            0 : TALER_PQ_query_param_exchange_blinding_values (
     493              :   const struct TALER_ExchangeBlindingValues *blinding_values)
     494              : {
     495            0 :   struct GNUNET_PQ_QueryParam res = {
     496              :     .conv = &qconv_exchange_blinding_values,
     497              :     .data = blinding_values,
     498              :     .num_params = 1
     499              :   };
     500              : 
     501            0 :   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           76 : 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           76 :   const json_t *json = data;
     531              :   char *str;
     532              : 
     533              :   (void) cls;
     534              :   (void) data_len;
     535           76 :   GNUNET_assert (1 == param_length);
     536           76 :   GNUNET_assert (scratch_length > 0);
     537           76 :   str = json_dumps (json,
     538              :                     JSON_COMPACT);
     539           76 :   if (NULL == str)
     540              :   {
     541            0 :     GNUNET_break (0);
     542            0 :     return -1;
     543              :   }
     544           76 :   scratch[0] = str;
     545           76 :   param_values[0] = (void *) str;
     546           76 :   param_lengths[0] = strlen (str);
     547           76 :   param_formats[0] = 1;
     548           76 :   return 1;
     549              : }
     550              : 
     551              : 
     552              : struct GNUNET_PQ_QueryParam
     553           76 : TALER_PQ_query_param_json (const json_t *x)
     554              : {
     555           76 :   struct GNUNET_PQ_QueryParam res = {
     556              :     .conv = &qconv_json,
     557              :     .data = x,
     558              :     .num_params = 1
     559              :   };
     560              : 
     561           76 :   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          468 : qconv_array_cls_cleanup (void *cls)
     618              : {
     619          468 :   GNUNET_free (cls);
     620          468 : }
     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          472 : 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          472 :   struct qconv_array_cls *meta = cls;
     654          472 :   size_t num = data_len;
     655              :   size_t total_size;
     656              :   const size_t *sizes;
     657              :   bool same_sized;
     658          472 :   void *elements = NULL;
     659          472 :   bool noerror = true;
     660              :   /* needed to capture the encoded rsa signatures */
     661          472 :   void **buffers = NULL;
     662          472 :   size_t *buffer_lengths = NULL;
     663              : 
     664              :   (void) (param_length);
     665              :   (void) (scratch_length);
     666              : 
     667          472 :   GNUNET_assert (NULL != meta);
     668          472 :   GNUNET_assert (num < INT_MAX);
     669              : 
     670          472 :   sizes = meta->sizes;
     671          472 :   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          472 :     size_t x = sizeof(uint32_t);
     687          472 :     size_t y = x * num;
     688          472 :     RETURN_UNLESS ((0 == num) || (y / num == x));
     689              : 
     690              :     /* size of header */
     691          472 :     total_size  = x = sizeof(struct GNUNET_PQ_ArrayHeader_P);
     692          472 :     total_size += y;
     693          472 :     RETURN_UNLESS (total_size >= x);
     694              : 
     695              :     /* sizes of elements */
     696          472 :     if (same_sized)
     697              :     {
     698          371 :       x = num * meta->same_size;
     699          371 :       RETURN_UNLESS ((0 == num) || (x / num == meta->same_size));
     700              : 
     701          371 :       y = total_size;
     702          371 :       total_size += x;
     703          371 :       RETURN_UNLESS (total_size >= y);
     704              :     }
     705              :     else  /* sizes are different per element */
     706              :     {
     707          101 :       switch (meta->typ)
     708              :       {
     709            1 :       case TALER_PQ_array_of_amount_currency:
     710              :         {
     711            1 :           const struct TALER_Amount *amounts = data;
     712              :           Oid oid_v;
     713              :           Oid oid_f;
     714              :           Oid oid_c;
     715              : 
     716            1 :           buffer_lengths  = GNUNET_new_array (num, size_t);
     717              :           /* hoist out of loop? */
     718            1 :           GNUNET_assert (GNUNET_OK ==
     719              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     720              :                                                     "int8",
     721              :                                                     &oid_v));
     722            1 :           GNUNET_assert (GNUNET_OK ==
     723              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     724              :                                                     "int4",
     725              :                                                     &oid_f));
     726            1 :           GNUNET_assert (GNUNET_OK ==
     727              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     728              :                                                     "varchar",
     729              :                                                     &oid_c));
     730            3 :           for (size_t i = 0; i<num; i++)
     731              :           {
     732              :             struct TALER_PQ_AmountCurrencyP am;
     733              :             size_t len;
     734              : 
     735            2 :             len = TALER_PQ_make_taler_pq_amount_currency_ (
     736            2 :               &amounts[i],
     737              :               oid_v,
     738              :               oid_f,
     739              :               oid_c,
     740              :               &am);
     741            2 :             buffer_lengths[i] = len;
     742            2 :             y = total_size;
     743            2 :             total_size += len;
     744            2 :             RETURN_UNLESS (total_size >= y);
     745              :           }
     746            1 :           sizes = buffer_lengths;
     747            1 :           break;
     748              :         }
     749          100 :       case TALER_PQ_array_of_blinded_denom_sig:
     750              :         {
     751          100 :           const struct TALER_BlindedDenominationSignature *denom_sigs = data;
     752              :           size_t len;
     753              : 
     754          100 :           buffers  = GNUNET_new_array (num, void *);
     755          100 :           buffer_lengths  = GNUNET_new_array (num, size_t);
     756              : 
     757          293 :           for (size_t i = 0; i<num; i++)
     758              :           {
     759          193 :             const struct GNUNET_CRYPTO_BlindedSignature *bs =
     760          193 :               denom_sigs[i].blinded_sig;
     761              : 
     762          193 :             switch (bs->cipher)
     763              :             {
     764           96 :             case GNUNET_CRYPTO_BSA_RSA:
     765           96 :               len = GNUNET_CRYPTO_rsa_signature_encode (
     766           96 :                 bs->details.blinded_rsa_signature,
     767           96 :                 &buffers[i]);
     768           96 :               RETURN_UNLESS (len != 0);
     769           96 :               break;
     770           97 :             case GNUNET_CRYPTO_BSA_CS:
     771           97 :               len = sizeof (bs->details.blinded_cs_answer);
     772           97 :               break;
     773            0 :             default:
     774            0 :               GNUNET_assert (0);
     775              :             }
     776              : 
     777              :             /* for the cipher and marker */
     778          193 :             len += 2 * sizeof(uint32_t);
     779          193 :             buffer_lengths[i] = len;
     780              : 
     781          193 :             y = total_size;
     782          193 :             total_size += len;
     783          193 :             RETURN_UNLESS (total_size >= y);
     784              :           }
     785          100 :           sizes = buffer_lengths;
     786          100 :           break;
     787              :         }
     788            0 :       default:
     789            0 :         GNUNET_assert (0);
     790              :       }
     791              :     }
     792              : 
     793          472 :     RETURN_UNLESS (INT_MAX > total_size);
     794          472 :     RETURN_UNLESS (0 != total_size);
     795              : 
     796          472 :     elements = GNUNET_malloc (total_size);
     797              :   }
     798              : 
     799              :   /* Write data */
     800              :   {
     801          472 :     char *out = elements;
     802          472 :     struct GNUNET_PQ_ArrayHeader_P h = {
     803          472 :       .ndim = htonl (1),        /* We only support one-dimensional arrays */
     804          472 :       .has_null = htonl (0),    /* We do not support NULL entries in arrays */
     805          472 :       .lbound = htonl (1),      /* Default start index value */
     806          472 :       .dim = htonl (num),
     807          472 :       .oid = htonl (meta->oid),
     808              :     };
     809              : 
     810              :     /* Write header */
     811          472 :     GNUNET_memcpy (out,
     812              :                    &h,
     813              :                    sizeof(h));
     814          472 :     out += sizeof(h);
     815              : 
     816              :     /* Write elements */
     817         1299 :     for (size_t i = 0; i < num; i++)
     818              :     {
     819          827 :       size_t sz = same_sized ? meta->same_size : sizes[i];
     820              : 
     821          827 :       *(uint32_t *) out = htonl (sz);
     822          827 :       out += sizeof(uint32_t);
     823          827 :       switch (meta->typ)
     824              :       {
     825          528 :       case TALER_PQ_array_of_amount:
     826              :         {
     827          528 :           const struct TALER_Amount *amounts = data;
     828              :           Oid oid_v;
     829              :           Oid oid_f;
     830              : 
     831              :           /* hoist out of loop? */
     832          528 :           GNUNET_assert (GNUNET_OK ==
     833              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     834              :                                                     "int8",
     835              :                                                     &oid_v));
     836          528 :           GNUNET_assert (GNUNET_OK ==
     837              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     838              :                                                     "int4",
     839              :                                                     &oid_f));
     840              :           {
     841              :             struct TALER_PQ_AmountP am
     842          528 :               = TALER_PQ_make_taler_pq_amount_ (
     843          528 :                   &amounts[i],
     844              :                   oid_v,
     845              :                   oid_f);
     846              : 
     847          528 :             GNUNET_memcpy (out,
     848              :                            &am,
     849              :                            sizeof(am));
     850              :           }
     851          528 :           break;
     852              :         }
     853            2 :       case TALER_PQ_array_of_amount_currency:
     854              :         {
     855            2 :           const struct TALER_Amount *amounts = data;
     856              :           Oid oid_v;
     857              :           Oid oid_f;
     858              :           Oid oid_c;
     859              : 
     860              :           /* hoist out of loop? */
     861            2 :           GNUNET_assert (GNUNET_OK ==
     862              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     863              :                                                     "int8",
     864              :                                                     &oid_v));
     865            2 :           GNUNET_assert (GNUNET_OK ==
     866              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     867              :                                                     "int4",
     868              :                                                     &oid_f));
     869            2 :           GNUNET_assert (GNUNET_OK ==
     870              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     871              :                                                     "varchar",
     872              :                                                     &oid_c));
     873              :           {
     874              :             struct TALER_PQ_AmountCurrencyP am;
     875              :             size_t len;
     876              : 
     877            2 :             len = TALER_PQ_make_taler_pq_amount_currency_ (
     878            2 :               &amounts[i],
     879              :               oid_v,
     880              :               oid_f,
     881              :               oid_c,
     882              :               &am);
     883            2 :             GNUNET_memcpy (out,
     884              :                            &am,
     885              :                            len);
     886              :           }
     887            2 :           break;
     888              :         }
     889          193 :       case TALER_PQ_array_of_blinded_denom_sig:
     890              :         {
     891          193 :           const struct TALER_BlindedDenominationSignature *denom_sigs = data;
     892          193 :           const struct GNUNET_CRYPTO_BlindedSignature *bs =
     893          193 :             denom_sigs[i].blinded_sig;
     894              :           uint32_t be[2];
     895              : 
     896          193 :           be[0] = htonl ((uint32_t) bs->cipher);
     897          193 :           be[1] = htonl (0x01);     /* magic margker: blinded */
     898          193 :           GNUNET_memcpy (out,
     899              :                          &be,
     900              :                          sizeof(be));
     901          193 :           out += sizeof(be);
     902          193 :           sz -= sizeof(be);
     903              : 
     904          193 :           switch (bs->cipher)
     905              :           {
     906           96 :           case GNUNET_CRYPTO_BSA_RSA:
     907              :             /* For RSA, 'same_sized' must have been false */
     908           96 :             GNUNET_assert (NULL != buffers);
     909           96 :             GNUNET_memcpy (out,
     910              :                            buffers[i],
     911              :                            sz);
     912           96 :             break;
     913           97 :           case GNUNET_CRYPTO_BSA_CS:
     914           97 :             GNUNET_memcpy (out,
     915              :                            &bs->details.blinded_cs_answer,
     916              :                            sz);
     917           97 :             break;
     918            0 :           default:
     919            0 :             GNUNET_assert (0);
     920              :           }
     921          193 :           break;
     922              :         }
     923            0 :       case TALER_PQ_array_of_blinded_coin_hash:
     924              :         {
     925            0 :           const struct TALER_BlindedCoinHashP *coin_hs = data;
     926              : 
     927            0 :           GNUNET_memcpy (out,
     928              :                          &coin_hs[i],
     929              :                          sizeof(struct TALER_BlindedCoinHashP));
     930              : 
     931            0 :           break;
     932              :         }
     933            0 :       case TALER_PQ_array_of_denom_hash:
     934              :         {
     935            0 :           const struct TALER_DenominationHashP *denom_hs = data;
     936              : 
     937            0 :           GNUNET_memcpy (out,
     938              :                          &denom_hs[i],
     939              :                          sizeof(struct TALER_DenominationHashP));
     940            0 :           break;
     941              :         }
     942            2 :       case TALER_PQ_array_of_hash_code:
     943              :         {
     944            2 :           const struct GNUNET_HashCode *hashes = data;
     945              : 
     946            2 :           GNUNET_memcpy (out,
     947              :                          &hashes[i],
     948              :                          sizeof(struct GNUNET_HashCode));
     949            2 :           break;
     950              :         }
     951          102 :       case TALER_PQ_array_of_cs_r_pub:
     952              :         {
     953          102 :           const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs = data;
     954              : 
     955          102 :           GNUNET_memcpy (out,
     956              :                          &cs_r_pubs[i],
     957              :                          sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
     958          102 :           break;
     959              :         }
     960            0 :       default:
     961              :         {
     962            0 :           GNUNET_assert (0);
     963              :           break;
     964              :         }
     965              :       }
     966          827 :       out += sz;
     967              :     }
     968              :   }
     969          472 :   param_values[0] = elements;
     970          472 :   param_lengths[0] = total_size;
     971          472 :   param_formats[0] = 1;
     972          472 :   scratch[0] = elements;
     973              : 
     974          472 : DONE:
     975          472 :   if (NULL != buffers)
     976              :   {
     977          293 :     for (size_t i = 0; i<num; i++)
     978          193 :       GNUNET_free (buffers[i]);
     979          100 :     GNUNET_free (buffers);
     980              :   }
     981          472 :   GNUNET_free (buffer_lengths);
     982          472 :   if (noerror)
     983          472 :     return 1;
     984            0 :   return -1;
     985              : }
     986              : 
     987              : 
     988              : /**
     989              :  * Function to generate a typ specific query parameter and corresponding closure
     990              :  *
     991              :  * @param num Number of elements in @a elements
     992              :  * @param continuous If true, @a elements is an continuous array of data
     993              :  * @param elements Array of @a num elements, either continuous or pointers
     994              :  * @param sizes Array of @a num sizes, one per element, may be NULL
     995              :  * @param same_size If not 0, all elements in @a elements have this size
     996              :  * @param typ Supported internal type of each element in @a elements
     997              :  * @param oid Oid of the type to be used in Postgres
     998              :  * @param[in,out] db our database handle for looking up OIDs
     999              :  * @return Query parameter
    1000              :  */
    1001              : static struct GNUNET_PQ_QueryParam
    1002          472 : query_param_array_generic (
    1003              :   unsigned int num,
    1004              :   bool continuous,
    1005              :   const void *elements,
    1006              :   const size_t *sizes,
    1007              :   size_t same_size,
    1008              :   enum TALER_PQ_ArrayType typ,
    1009              :   Oid oid,
    1010              :   struct GNUNET_PQ_Context *db)
    1011              : {
    1012          472 :   struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls);
    1013              : 
    1014          472 :   meta->typ = typ;
    1015          472 :   meta->oid = oid;
    1016          472 :   meta->sizes = sizes;
    1017          472 :   meta->same_size = same_size;
    1018          472 :   meta->continuous = continuous;
    1019          472 :   meta->db = db;
    1020              : 
    1021              :   {
    1022          472 :     struct GNUNET_PQ_QueryParam res = {
    1023              :       .conv = qconv_array,
    1024              :       .conv_cls = meta,
    1025              :       .conv_cls_cleanup = qconv_array_cls_cleanup,
    1026              :       .data = elements,
    1027              :       .size = num,
    1028              :       .num_params = 1,
    1029              :     };
    1030              : 
    1031          472 :     return res;
    1032              :   }
    1033              : }
    1034              : 
    1035              : 
    1036              : struct GNUNET_PQ_QueryParam
    1037          100 : TALER_PQ_query_param_array_blinded_denom_sig (
    1038              :   size_t num,
    1039              :   const struct TALER_BlindedDenominationSignature *denom_sigs,
    1040              :   struct GNUNET_PQ_Context *db)
    1041              : {
    1042              :   Oid oid;
    1043              : 
    1044          100 :   GNUNET_assert (GNUNET_OK ==
    1045              :                  GNUNET_PQ_get_oid_by_name (db,
    1046              :                                             "bytea",
    1047              :                                             &oid));
    1048          100 :   return query_param_array_generic (num,
    1049              :                                     true,
    1050              :                                     denom_sigs,
    1051              :                                     NULL,
    1052              :                                     0,
    1053              :                                     TALER_PQ_array_of_blinded_denom_sig,
    1054              :                                     oid,
    1055              :                                     NULL);
    1056              : }
    1057              : 
    1058              : 
    1059              : struct GNUNET_PQ_QueryParam
    1060            0 : TALER_PQ_query_param_array_blinded_coin_hash (
    1061              :   size_t num,
    1062              :   const struct TALER_BlindedCoinHashP *coin_hs,
    1063              :   struct GNUNET_PQ_Context *db)
    1064              : {
    1065              :   Oid oid;
    1066              : 
    1067            0 :   GNUNET_assert (GNUNET_OK ==
    1068              :                  GNUNET_PQ_get_oid_by_name (db,
    1069              :                                             "bytea",
    1070              :                                             &oid));
    1071            0 :   return query_param_array_generic (num,
    1072              :                                     true,
    1073              :                                     coin_hs,
    1074              :                                     NULL,
    1075              :                                     sizeof(struct TALER_BlindedCoinHashP),
    1076              :                                     TALER_PQ_array_of_blinded_coin_hash,
    1077              :                                     oid,
    1078              :                                     NULL);
    1079              : }
    1080              : 
    1081              : 
    1082              : struct GNUNET_PQ_QueryParam
    1083            0 : TALER_PQ_query_param_array_denom_hash (
    1084              :   size_t num,
    1085              :   const struct TALER_DenominationHashP *denom_hs,
    1086              :   struct GNUNET_PQ_Context *db)
    1087              : {
    1088              :   Oid oid;
    1089              : 
    1090            0 :   GNUNET_assert (GNUNET_OK ==
    1091              :                  GNUNET_PQ_get_oid_by_name (db,
    1092              :                                             "bytea",
    1093              :                                             &oid));
    1094            0 :   return query_param_array_generic (num,
    1095              :                                     true,
    1096              :                                     denom_hs,
    1097              :                                     NULL,
    1098              :                                     sizeof(struct TALER_DenominationHashP),
    1099              :                                     TALER_PQ_array_of_denom_hash,
    1100              :                                     oid,
    1101              :                                     NULL);
    1102              : }
    1103              : 
    1104              : 
    1105              : struct GNUNET_PQ_QueryParam
    1106            1 : TALER_PQ_query_param_array_hash_code (
    1107              :   size_t num,
    1108              :   const struct GNUNET_HashCode *hashes,
    1109              :   struct GNUNET_PQ_Context *db)
    1110              : {
    1111              :   Oid oid;
    1112            1 :   GNUNET_assert (GNUNET_OK ==
    1113              :                  GNUNET_PQ_get_oid_by_name (db, "gnunet_hashcode", &oid));
    1114            1 :   return query_param_array_generic (num,
    1115              :                                     true,
    1116              :                                     hashes,
    1117              :                                     NULL,
    1118              :                                     sizeof(struct GNUNET_HashCode),
    1119              :                                     TALER_PQ_array_of_hash_code,
    1120              :                                     oid,
    1121              :                                     NULL);
    1122              : }
    1123              : 
    1124              : 
    1125              : struct GNUNET_PQ_QueryParam
    1126          320 : TALER_PQ_query_param_array_amount (
    1127              :   size_t num,
    1128              :   const struct TALER_Amount *amounts,
    1129              :   struct GNUNET_PQ_Context *db)
    1130              : {
    1131              :   Oid oid;
    1132              : 
    1133          320 :   GNUNET_assert (GNUNET_OK ==
    1134              :                  GNUNET_PQ_get_oid_by_name (db,
    1135              :                                             "taler_amount",
    1136              :                                             &oid));
    1137          320 :   return query_param_array_generic (
    1138              :     num,
    1139              :     true,
    1140              :     amounts,
    1141              :     NULL,
    1142              :     sizeof(struct TALER_PQ_AmountP),
    1143              :     TALER_PQ_array_of_amount,
    1144              :     oid,
    1145              :     db);
    1146              : }
    1147              : 
    1148              : 
    1149              : struct GNUNET_PQ_QueryParam
    1150            1 : TALER_PQ_query_param_array_amount_with_currency (
    1151              :   size_t num,
    1152              :   const struct TALER_Amount *amounts,
    1153              :   struct GNUNET_PQ_Context *db)
    1154              : {
    1155              :   Oid oid;
    1156              : 
    1157            1 :   GNUNET_assert (GNUNET_OK ==
    1158              :                  GNUNET_PQ_get_oid_by_name (db,
    1159              :                                             "taler_amount_currency",
    1160              :                                             &oid));
    1161            1 :   return query_param_array_generic (
    1162              :     num,
    1163              :     true,
    1164              :     amounts,
    1165              :     NULL,
    1166              :     0, /* currency is technically variable length */
    1167              :     TALER_PQ_array_of_amount_currency,
    1168              :     oid,
    1169              :     db);
    1170              : }
    1171              : 
    1172              : 
    1173              : struct GNUNET_PQ_QueryParam
    1174           50 : TALER_PQ_query_param_array_cs_r_pub (
    1175              :   size_t num,
    1176              :   const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs,
    1177              :   struct GNUNET_PQ_Context *db)
    1178              : {
    1179              :   Oid oid;
    1180              : 
    1181           50 :   GNUNET_assert (GNUNET_OK ==
    1182              :                  GNUNET_PQ_get_oid_by_name (db,
    1183              :                                             "bytea",
    1184              :                                             &oid));
    1185           50 :   return query_param_array_generic (
    1186              :     num,
    1187              :     true,
    1188              :     cs_r_pubs,
    1189              :     NULL,
    1190              :     sizeof(struct GNUNET_CRYPTO_CSPublicRPairP),
    1191              :     TALER_PQ_array_of_cs_r_pub,
    1192              :     oid,
    1193              :     db);
    1194              : }
    1195              : 
    1196              : 
    1197              : /* end of pq/pq_query_helper.c */
        

Generated by: LCOV version 2.0-1