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-01-09 13:26:54 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 "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            1 : 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            1 :   struct GNUNET_PQ_Context *db = cls;
      57            1 :   const struct TALER_Amount *amount = data;
      58              :   size_t sz;
      59              : 
      60            1 :   GNUNET_assert (NULL != db);
      61            1 :   GNUNET_assert (NULL != amount);
      62            1 :   GNUNET_assert (1 == param_length);
      63            1 :   GNUNET_assert (1 <= scratch_length);
      64            1 :   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            1 :     GNUNET_assert (GNUNET_OK ==
      74              :                    GNUNET_PQ_get_oid_by_name (db,
      75              :                                               "int8",
      76              :                                               &oid_v));
      77            1 :     GNUNET_assert (GNUNET_OK ==
      78              :                    GNUNET_PQ_get_oid_by_name (db,
      79              :                                               "int4",
      80              :                                               &oid_f));
      81            1 :     GNUNET_assert (GNUNET_OK ==
      82              :                    GNUNET_PQ_get_oid_by_name (db,
      83              :                                               "varchar",
      84              :                                               &oid_c));
      85            1 :     sz = TALER_PQ_make_taler_pq_amount_currency_ (amount,
      86              :                                                   oid_v,
      87              :                                                   oid_f,
      88              :                                                   oid_c,
      89              :                                                   &d);
      90            1 :     out = GNUNET_malloc (sz);
      91            1 :     memcpy (out,
      92              :             &d,
      93              :             sz);
      94            1 :     scratch[0] = out;
      95              :   }
      96              : 
      97            1 :   param_values[0] = scratch[0];
      98            1 :   param_lengths[0] = sz;
      99            1 :   param_formats[0] = 1;
     100              : 
     101            1 :   return 1;
     102              : }
     103              : 
     104              : 
     105              : struct GNUNET_PQ_QueryParam
     106            1 : TALER_PQ_query_param_amount_with_currency (
     107              :   const struct GNUNET_PQ_Context *db,
     108              :   const struct TALER_Amount *amount)
     109              : {
     110            1 :   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            1 :   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        27678 : 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        27678 :   struct GNUNET_PQ_Context *db = cls;
     148        27678 :   const struct TALER_Amount *amount = data;
     149              :   size_t sz;
     150              : 
     151        27678 :   GNUNET_assert (NULL != db);
     152        27678 :   GNUNET_assert (NULL != amount);
     153        27678 :   GNUNET_assert (1 == param_length);
     154        27678 :   GNUNET_assert (1 <= scratch_length);
     155        27678 :   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        27678 :     GNUNET_assert (GNUNET_OK ==
     163              :                    GNUNET_PQ_get_oid_by_name (db,
     164              :                                               "int8",
     165              :                                               &oid_v));
     166        27678 :     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        27678 :         = TALER_PQ_make_taler_pq_amount_ (amount,
     174              :                                           oid_v,
     175              :                                           oid_f);
     176              : 
     177        27678 :       sz = sizeof(d);
     178        27678 :       out = GNUNET_malloc (sz);
     179        27678 :       scratch[0] = out;
     180        27678 :       GNUNET_memcpy (out,
     181              :                      &d,
     182              :                      sizeof(d));
     183              :     }
     184              :   }
     185              : 
     186        27678 :   param_values[0] = scratch[0];
     187        27678 :   param_lengths[0] = sz;
     188        27678 :   param_formats[0] = 1;
     189              : 
     190        27678 :   return 1;
     191              : }
     192              : 
     193              : 
     194              : struct GNUNET_PQ_QueryParam
     195        27678 : TALER_PQ_query_param_amount (
     196              :   const struct GNUNET_PQ_Context *db,
     197              :   const struct TALER_Amount *amount)
     198              : {
     199        27678 :   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        27678 :   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         5397 : 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         5397 :   const struct TALER_DenominationPublicKey *denom_pub = data;
     237         5397 :   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         5397 :   GNUNET_assert (1 == param_length);
     247         5397 :   GNUNET_assert (scratch_length > 0);
     248         5397 :   GNUNET_break (NULL == cls);
     249         5397 :   be[0] = htonl ((uint32_t) bsp->cipher);
     250         5397 :   be[1] = htonl (denom_pub->age_mask.bits);
     251         5397 :   switch (bsp->cipher)
     252              :   {
     253         2734 :   case GNUNET_CRYPTO_BSA_RSA:
     254         2734 :     tlen = GNUNET_CRYPTO_rsa_public_key_encode (
     255         2734 :       bsp->details.rsa_public_key,
     256              :       &tbuf);
     257         2734 :     break;
     258         2663 :   case GNUNET_CRYPTO_BSA_CS:
     259         2663 :     tlen = sizeof (bsp->details.cs_public_key);
     260         2663 :     break;
     261            0 :   default:
     262            0 :     GNUNET_assert (0);
     263              :   }
     264         5397 :   len = tlen + sizeof (be);
     265         5397 :   buf = GNUNET_malloc (len);
     266         5397 :   GNUNET_memcpy (buf,
     267              :                  be,
     268              :                  sizeof (be));
     269         5397 :   switch (bsp->cipher)
     270              :   {
     271         2734 :   case GNUNET_CRYPTO_BSA_RSA:
     272         2734 :     GNUNET_memcpy (&buf[sizeof (be)],
     273              :                    tbuf,
     274              :                    tlen);
     275         2734 :     GNUNET_free (tbuf);
     276         2734 :     break;
     277         2663 :   case GNUNET_CRYPTO_BSA_CS:
     278         2663 :     GNUNET_memcpy (&buf[sizeof (be)],
     279              :                    &bsp->details.cs_public_key,
     280              :                    tlen);
     281         2663 :     break;
     282            0 :   default:
     283            0 :     GNUNET_assert (0);
     284              :   }
     285              : 
     286         5397 :   scratch[0] = buf;
     287         5397 :   param_values[0] = (void *) buf;
     288         5397 :   param_lengths[0] = len;
     289         5397 :   param_formats[0] = 1;
     290         5397 :   return 1;
     291              : }
     292              : 
     293              : 
     294              : struct GNUNET_PQ_QueryParam
     295         5397 : TALER_PQ_query_param_denom_pub (
     296              :   const struct TALER_DenominationPublicKey *denom_pub)
     297              : {
     298         5397 :   struct GNUNET_PQ_QueryParam res = {
     299              :     .conv = &qconv_denom_pub,
     300              :     .data = denom_pub,
     301              :     .num_params = 1
     302              :   };
     303              : 
     304         5397 :   return res;
     305              : }
     306              : 
     307              : 
     308              : struct GNUNET_PQ_QueryParam
     309          169 : TALER_PQ_query_param_denom_sig (
     310              :   const struct TALER_DenominationSignature *denom_sig)
     311              : {
     312          169 :   return GNUNET_PQ_query_param_unblinded_sig (denom_sig->unblinded_sig);
     313              : }
     314              : 
     315              : 
     316              : struct GNUNET_PQ_QueryParam
     317            0 : TALER_PQ_query_param_blinded_denom_sig (
     318              :   const struct TALER_BlindedDenominationSignature *denom_sig)
     319              : {
     320            0 :   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            0 : 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            0 :   const struct TALER_BlindedPlanchet *bp = data;
     350            0 :   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            0 :   GNUNET_assert (1 == param_length);
     359            0 :   GNUNET_assert (scratch_length > 0);
     360            0 :   GNUNET_break (NULL == cls);
     361            0 :   be[0] = htonl ((uint32_t) bm->cipher);
     362            0 :   be[1] = htonl (0x0100); /* magic marker: blinded */
     363            0 :   switch (bm->cipher)
     364              :   {
     365            0 :   case GNUNET_CRYPTO_BSA_RSA:
     366            0 :     tlen = bm->details.rsa_blinded_message.blinded_msg_size;
     367            0 :     break;
     368            0 :   case GNUNET_CRYPTO_BSA_CS:
     369            0 :     tlen = sizeof (bm->details.cs_blinded_message);
     370            0 :     break;
     371            0 :   default:
     372            0 :     GNUNET_assert (0);
     373              :   }
     374            0 :   len = tlen + sizeof (be);
     375            0 :   buf = GNUNET_malloc (len);
     376            0 :   GNUNET_memcpy (buf,
     377              :                  &be,
     378              :                  sizeof (be));
     379            0 :   switch (bm->cipher)
     380              :   {
     381            0 :   case GNUNET_CRYPTO_BSA_RSA:
     382            0 :     GNUNET_memcpy (&buf[sizeof (be)],
     383              :                    bm->details.rsa_blinded_message.blinded_msg,
     384              :                    tlen);
     385            0 :     break;
     386            0 :   case GNUNET_CRYPTO_BSA_CS:
     387            0 :     GNUNET_memcpy (&buf[sizeof (be)],
     388              :                    &bm->details.cs_blinded_message,
     389              :                    tlen);
     390            0 :     break;
     391            0 :   default:
     392            0 :     GNUNET_assert (0);
     393              :   }
     394            0 :   scratch[0] = buf;
     395            0 :   param_values[0] = (void *) buf;
     396            0 :   param_lengths[0] = len;
     397            0 :   param_formats[0] = 1;
     398            0 :   return 1;
     399              : }
     400              : 
     401              : 
     402              : struct GNUNET_PQ_QueryParam
     403            0 : TALER_PQ_query_param_blinded_planchet (
     404              :   const struct TALER_BlindedPlanchet *bp)
     405              : {
     406            0 :   struct GNUNET_PQ_QueryParam res = {
     407              :     .conv = &qconv_blinded_planchet,
     408              :     .data = bp,
     409              :     .num_params = 1
     410              :   };
     411              : 
     412            0 :   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            0 : 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            0 :   const struct TALER_ExchangeBlindingValues *blinding_values = data;
     442            0 :   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            0 :   GNUNET_assert (1 == param_length);
     452            0 :   GNUNET_assert (scratch_length > 0);
     453            0 :   GNUNET_break (NULL == cls);
     454            0 :   be[0] = htonl ((uint32_t) bi->cipher);
     455            0 :   be[1] = htonl (0x010000); /* magic marker: EWV */
     456            0 :   switch (bi->cipher)
     457              :   {
     458            0 :   case GNUNET_CRYPTO_BSA_RSA:
     459            0 :     tlen = 0;
     460            0 :     break;
     461            0 :   case GNUNET_CRYPTO_BSA_CS:
     462            0 :     tlen = sizeof (struct GNUNET_CRYPTO_CSPublicRPairP);
     463            0 :     break;
     464            0 :   default:
     465            0 :     GNUNET_assert (0);
     466              :   }
     467            0 :   len = tlen + sizeof (be);
     468            0 :   buf = GNUNET_malloc (len);
     469            0 :   GNUNET_memcpy (buf,
     470              :                  &be,
     471              :                  sizeof (be));
     472            0 :   switch (bi->cipher)
     473              :   {
     474            0 :   case GNUNET_CRYPTO_BSA_RSA:
     475            0 :     break;
     476            0 :   case GNUNET_CRYPTO_BSA_CS:
     477            0 :     GNUNET_memcpy (&buf[sizeof (be)],
     478              :                    &bi->details.cs_values,
     479              :                    tlen);
     480            0 :     break;
     481            0 :   default:
     482            0 :     GNUNET_assert (0);
     483              :   }
     484            0 :   scratch[0] = buf;
     485            0 :   param_values[0] = (void *) buf;
     486            0 :   param_lengths[0] = len;
     487            0 :   param_formats[0] = 1;
     488            0 :   return 1;
     489              : }
     490              : 
     491              : 
     492              : struct GNUNET_PQ_QueryParam
     493            0 : TALER_PQ_query_param_exchange_blinding_values (
     494              :   const struct TALER_ExchangeBlindingValues *blinding_values)
     495              : {
     496            0 :   struct GNUNET_PQ_QueryParam res = {
     497              :     .conv = &qconv_exchange_blinding_values,
     498              :     .data = blinding_values,
     499              :     .num_params = 1
     500              :   };
     501              : 
     502            0 :   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           78 : 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           78 :   const json_t *json = data;
     532              :   char *str;
     533              : 
     534              :   (void) cls;
     535              :   (void) data_len;
     536           78 :   GNUNET_assert (1 == param_length);
     537           78 :   GNUNET_assert (scratch_length > 0);
     538           78 :   str = json_dumps (json,
     539              :                     JSON_COMPACT);
     540           78 :   if (NULL == str)
     541              :   {
     542            0 :     GNUNET_break (0);
     543            0 :     return -1;
     544              :   }
     545           78 :   scratch[0] = str;
     546           78 :   param_values[0] = (void *) str;
     547           78 :   param_lengths[0] = strlen (str);
     548           78 :   param_formats[0] = 1;
     549           78 :   return 1;
     550              : }
     551              : 
     552              : 
     553              : struct GNUNET_PQ_QueryParam
     554           78 : TALER_PQ_query_param_json (const json_t *x)
     555              : {
     556           78 :   struct GNUNET_PQ_QueryParam res = {
     557              :     .conv = &qconv_json,
     558              :     .data = x,
     559              :     .num_params = 1
     560              :   };
     561              : 
     562           78 :   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          353 : qconv_array_cls_cleanup (void *cls)
     619              : {
     620          353 :   GNUNET_free (cls);
     621          353 : }
     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          357 : 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          357 :   struct qconv_array_cls *meta = cls;
     655          357 :   size_t num = data_len;
     656              :   size_t total_size;
     657              :   const size_t *sizes;
     658              :   bool same_sized;
     659          357 :   void *elements = NULL;
     660          357 :   bool noerror = true;
     661              :   /* needed to capture the encoded rsa signatures */
     662          357 :   void **buffers = NULL;
     663          357 :   size_t *buffer_lengths = NULL;
     664              : 
     665              :   (void) (param_length);
     666              :   (void) (scratch_length);
     667              : 
     668          357 :   GNUNET_assert (NULL != meta);
     669          357 :   GNUNET_assert (num < INT_MAX);
     670              : 
     671          357 :   sizes = meta->sizes;
     672          357 :   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          357 :     size_t x = sizeof(uint32_t);
     688          357 :     size_t y = x * num;
     689          357 :     RETURN_UNLESS ((0 == num) || (y / num == x));
     690              : 
     691              :     /* size of header */
     692          357 :     total_size  = x = sizeof(struct GNUNET_PQ_ArrayHeader_P);
     693          357 :     total_size += y;
     694          357 :     RETURN_UNLESS (total_size >= x);
     695              : 
     696              :     /* sizes of elements */
     697          357 :     if (same_sized)
     698              :     {
     699          256 :       x = num * meta->same_size;
     700          256 :       RETURN_UNLESS ((0 == num) || (x / num == meta->same_size));
     701              : 
     702          256 :       y = total_size;
     703          256 :       total_size += x;
     704          256 :       RETURN_UNLESS (total_size >= y);
     705              :     }
     706              :     else  /* sizes are different per element */
     707              :     {
     708          101 :       switch (meta->typ)
     709              :       {
     710            1 :       case TALER_PQ_array_of_amount_currency:
     711              :         {
     712            1 :           const struct TALER_Amount *amounts = data;
     713              :           Oid oid_v;
     714              :           Oid oid_f;
     715              :           Oid oid_c;
     716              : 
     717            1 :           buffer_lengths  = GNUNET_new_array (num, size_t);
     718              :           /* hoist out of loop? */
     719            1 :           GNUNET_assert (GNUNET_OK ==
     720              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     721              :                                                     "int8",
     722              :                                                     &oid_v));
     723            1 :           GNUNET_assert (GNUNET_OK ==
     724              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     725              :                                                     "int4",
     726              :                                                     &oid_f));
     727            1 :           GNUNET_assert (GNUNET_OK ==
     728              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     729              :                                                     "varchar",
     730              :                                                     &oid_c));
     731            3 :           for (size_t i = 0; i<num; i++)
     732              :           {
     733              :             struct TALER_PQ_AmountCurrencyP am;
     734              :             size_t len;
     735              : 
     736            2 :             len = TALER_PQ_make_taler_pq_amount_currency_ (
     737            2 :               &amounts[i],
     738              :               oid_v,
     739              :               oid_f,
     740              :               oid_c,
     741              :               &am);
     742            2 :             buffer_lengths[i] = len;
     743            2 :             y = total_size;
     744            2 :             total_size += len;
     745            2 :             RETURN_UNLESS (total_size >= y);
     746              :           }
     747            1 :           sizes = buffer_lengths;
     748            1 :           break;
     749              :         }
     750          100 :       case TALER_PQ_array_of_blinded_denom_sig:
     751              :         {
     752          100 :           const struct TALER_BlindedDenominationSignature *denom_sigs = data;
     753              :           size_t len;
     754              : 
     755          100 :           buffers  = GNUNET_new_array (num, void *);
     756          100 :           buffer_lengths  = GNUNET_new_array (num, size_t);
     757              : 
     758          293 :           for (size_t i = 0; i<num; i++)
     759              :           {
     760          193 :             const struct GNUNET_CRYPTO_BlindedSignature *bs =
     761          193 :               denom_sigs[i].blinded_sig;
     762              : 
     763          193 :             switch (bs->cipher)
     764              :             {
     765           96 :             case GNUNET_CRYPTO_BSA_RSA:
     766           96 :               len = GNUNET_CRYPTO_rsa_signature_encode (
     767           96 :                 bs->details.blinded_rsa_signature,
     768           96 :                 &buffers[i]);
     769           96 :               RETURN_UNLESS (len != 0);
     770           96 :               break;
     771           97 :             case GNUNET_CRYPTO_BSA_CS:
     772           97 :               len = sizeof (bs->details.blinded_cs_answer);
     773           97 :               break;
     774            0 :             default:
     775            0 :               GNUNET_assert (0);
     776              :             }
     777              : 
     778              :             /* for the cipher and marker */
     779          193 :             len += 2 * sizeof(uint32_t);
     780          193 :             buffer_lengths[i] = len;
     781              : 
     782          193 :             y = total_size;
     783          193 :             total_size += len;
     784          193 :             RETURN_UNLESS (total_size >= y);
     785              :           }
     786          100 :           sizes = buffer_lengths;
     787          100 :           break;
     788              :         }
     789            0 :       default:
     790            0 :         GNUNET_assert (0);
     791              :       }
     792              :     }
     793              : 
     794          357 :     RETURN_UNLESS (INT_MAX > total_size);
     795          357 :     RETURN_UNLESS (0 != total_size);
     796              : 
     797          357 :     elements = GNUNET_malloc (total_size);
     798              :   }
     799              : 
     800              :   /* Write data */
     801              :   {
     802          357 :     char *out = elements;
     803          357 :     struct GNUNET_PQ_ArrayHeader_P h = {
     804          357 :       .ndim = htonl (1),        /* We only support one-dimensional arrays */
     805          357 :       .has_null = htonl (0),    /* We do not support NULL entries in arrays */
     806          357 :       .lbound = htonl (1),      /* Default start index value */
     807          357 :       .dim = htonl (num),
     808          357 :       .oid = htonl (meta->oid),
     809              :     };
     810              : 
     811              :     /* Write header */
     812          357 :     GNUNET_memcpy (out,
     813              :                    &h,
     814              :                    sizeof(h));
     815          357 :     out += sizeof(h);
     816              : 
     817              :     /* Write elements */
     818         1079 :     for (size_t i = 0; i < num; i++)
     819              :     {
     820          722 :       size_t sz = same_sized ? meta->same_size : sizes[i];
     821              : 
     822          722 :       *(uint32_t *) out = htonl (sz);
     823          722 :       out += sizeof(uint32_t);
     824          722 :       switch (meta->typ)
     825              :       {
     826          423 :       case TALER_PQ_array_of_amount:
     827              :         {
     828          423 :           const struct TALER_Amount *amounts = data;
     829              :           Oid oid_v;
     830              :           Oid oid_f;
     831              : 
     832              :           /* hoist out of loop? */
     833          423 :           GNUNET_assert (GNUNET_OK ==
     834              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     835              :                                                     "int8",
     836              :                                                     &oid_v));
     837          423 :           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          423 :               = TALER_PQ_make_taler_pq_amount_ (
     844          423 :                   &amounts[i],
     845              :                   oid_v,
     846              :                   oid_f);
     847              : 
     848          423 :             GNUNET_memcpy (out,
     849              :                            &am,
     850              :                            sizeof(am));
     851              :           }
     852          423 :           break;
     853              :         }
     854            2 :       case TALER_PQ_array_of_amount_currency:
     855              :         {
     856            2 :           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            2 :           GNUNET_assert (GNUNET_OK ==
     863              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     864              :                                                     "int8",
     865              :                                                     &oid_v));
     866            2 :           GNUNET_assert (GNUNET_OK ==
     867              :                          GNUNET_PQ_get_oid_by_name (meta->db,
     868              :                                                     "int4",
     869              :                                                     &oid_f));
     870            2 :           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            2 :             len = TALER_PQ_make_taler_pq_amount_currency_ (
     879            2 :               &amounts[i],
     880              :               oid_v,
     881              :               oid_f,
     882              :               oid_c,
     883              :               &am);
     884            2 :             GNUNET_memcpy (out,
     885              :                            &am,
     886              :                            len);
     887              :           }
     888            2 :           break;
     889              :         }
     890          193 :       case TALER_PQ_array_of_blinded_denom_sig:
     891              :         {
     892          193 :           const struct TALER_BlindedDenominationSignature *denom_sigs = data;
     893          193 :           const struct GNUNET_CRYPTO_BlindedSignature *bs =
     894          193 :             denom_sigs[i].blinded_sig;
     895              :           uint32_t be[2];
     896              : 
     897          193 :           be[0] = htonl ((uint32_t) bs->cipher);
     898          193 :           be[1] = htonl (0x01);     /* magic margker: blinded */
     899          193 :           GNUNET_memcpy (out,
     900              :                          &be,
     901              :                          sizeof(be));
     902          193 :           out += sizeof(be);
     903          193 :           sz -= sizeof(be);
     904              : 
     905          193 :           switch (bs->cipher)
     906              :           {
     907           96 :           case GNUNET_CRYPTO_BSA_RSA:
     908              :             /* For RSA, 'same_sized' must have been false */
     909           96 :             GNUNET_assert (NULL != buffers);
     910           96 :             GNUNET_memcpy (out,
     911              :                            buffers[i],
     912              :                            sz);
     913           96 :             break;
     914           97 :           case GNUNET_CRYPTO_BSA_CS:
     915           97 :             GNUNET_memcpy (out,
     916              :                            &bs->details.blinded_cs_answer,
     917              :                            sz);
     918           97 :             break;
     919            0 :           default:
     920            0 :             GNUNET_assert (0);
     921              :           }
     922          193 :           break;
     923              :         }
     924            0 :       case TALER_PQ_array_of_blinded_coin_hash:
     925              :         {
     926            0 :           const struct TALER_BlindedCoinHashP *coin_hs = data;
     927              : 
     928            0 :           GNUNET_memcpy (out,
     929              :                          &coin_hs[i],
     930              :                          sizeof(struct TALER_BlindedCoinHashP));
     931              : 
     932            0 :           break;
     933              :         }
     934            0 :       case TALER_PQ_array_of_denom_hash:
     935              :         {
     936            0 :           const struct TALER_DenominationHashP *denom_hs = data;
     937              : 
     938            0 :           GNUNET_memcpy (out,
     939              :                          &denom_hs[i],
     940              :                          sizeof(struct TALER_DenominationHashP));
     941            0 :           break;
     942              :         }
     943            2 :       case TALER_PQ_array_of_hash_code:
     944              :         {
     945            2 :           const struct GNUNET_HashCode *hashes = data;
     946              : 
     947            2 :           GNUNET_memcpy (out,
     948              :                          &hashes[i],
     949              :                          sizeof(struct GNUNET_HashCode));
     950            2 :           break;
     951              :         }
     952          102 :       case TALER_PQ_array_of_cs_r_pub:
     953              :         {
     954          102 :           const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs = data;
     955              : 
     956          102 :           GNUNET_memcpy (out,
     957              :                          &cs_r_pubs[i],
     958              :                          sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
     959          102 :           break;
     960              :         }
     961            0 :       default:
     962              :         {
     963            0 :           GNUNET_assert (0);
     964              :           break;
     965              :         }
     966              :       }
     967          722 :       out += sz;
     968              :     }
     969              :   }
     970          357 :   param_values[0] = elements;
     971          357 :   param_lengths[0] = total_size;
     972          357 :   param_formats[0] = 1;
     973          357 :   scratch[0] = elements;
     974              : 
     975          357 : DONE:
     976          357 :   if (NULL != buffers)
     977              :   {
     978          293 :     for (size_t i = 0; i<num; i++)
     979          193 :       GNUNET_free (buffers[i]);
     980          100 :     GNUNET_free (buffers);
     981              :   }
     982          357 :   GNUNET_free (buffer_lengths);
     983          357 :   if (noerror)
     984          357 :     return 1;
     985            0 :   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          357 : 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          357 :   struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls);
    1014              : 
    1015          357 :   meta->typ = typ;
    1016          357 :   meta->oid = oid;
    1017          357 :   meta->sizes = sizes;
    1018          357 :   meta->same_size = same_size;
    1019          357 :   meta->continuous = continuous;
    1020          357 :   meta->db = db;
    1021              : 
    1022              :   {
    1023          357 :     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          357 :     return res;
    1033              :   }
    1034              : }
    1035              : 
    1036              : 
    1037              : struct GNUNET_PQ_QueryParam
    1038          100 : 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          100 :   GNUNET_assert (GNUNET_OK ==
    1046              :                  GNUNET_PQ_get_oid_by_name (db,
    1047              :                                             "bytea",
    1048              :                                             &oid));
    1049          100 :   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            0 : 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            0 :   GNUNET_assert (GNUNET_OK ==
    1069              :                  GNUNET_PQ_get_oid_by_name (db,
    1070              :                                             "bytea",
    1071              :                                             &oid));
    1072            0 :   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            0 : 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            0 :   GNUNET_assert (GNUNET_OK ==
    1092              :                  GNUNET_PQ_get_oid_by_name (db,
    1093              :                                             "bytea",
    1094              :                                             &oid));
    1095            0 :   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            1 : 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            1 :   GNUNET_assert (GNUNET_OK ==
    1114              :                  GNUNET_PQ_get_oid_by_name (db, "gnunet_hashcode", &oid));
    1115            1 :   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          205 : 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          205 :   GNUNET_assert (GNUNET_OK ==
    1135              :                  GNUNET_PQ_get_oid_by_name (db,
    1136              :                                             "taler_amount",
    1137              :                                             &oid));
    1138          205 :   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            1 : 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            1 :   GNUNET_assert (GNUNET_OK ==
    1159              :                  GNUNET_PQ_get_oid_by_name (db,
    1160              :                                             "taler_amount_currency",
    1161              :                                             &oid));
    1162            1 :   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           50 : 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           50 :   GNUNET_assert (GNUNET_OK ==
    1183              :                  GNUNET_PQ_get_oid_by_name (db,
    1184              :                                             "bytea",
    1185              :                                             &oid));
    1186           50 :   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 */
        

Generated by: LCOV version 2.0-1