creating libgnunetpq library
[oweals/gnunet.git] / src / pq / pq.c
1 /*
2   This file is part of GNUnet
3   Copyright (C) 2014, 2015, 2016 GNUnet e.V.
4
5   GNUnet 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   GNUnet 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   GNUnet; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/>
15 */
16 /**
17  * @file pq/pq.c
18  * @brief helper functions for libpq (PostGres) interactions
19  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
20  * @author Florian Dold
21  * @author Christian Grothoff
22  */
23 #include "platform.h"
24 #include <gnunet/gnunet_util_lib.h>
25 #include "gnunet_pq_lib.h"
26
27
28 /**
29  * Execute a prepared statement.
30  *
31  * @param db_conn database connection
32  * @param name name of the prepared statement
33  * @param params parameters to the statement
34  * @return postgres result
35  */
36 PGresult *
37 GNUNET_PQ_exec_prepared (PGconn *db_conn,
38                          const char *name,
39                          const struct GNUNET_PQ_QueryParam *params)
40 {
41   unsigned int len;
42   unsigned int i;
43
44   /* count the number of parameters */
45   len = 0;
46   for (i=0;0 != params[i].num_params;i++)
47     len += params[i].num_params;
48
49   /* new scope to allow stack allocation without alloca */
50   {
51     /* Scratch buffer for temporary storage */
52     void *scratch[len];
53     /* Parameter array we are building for the query */
54     void *param_values[len];
55     int param_lengths[len];
56     int param_formats[len];
57     unsigned int off;
58     /* How many entries in the scratch buffer are in use? */
59     unsigned int soff;
60     PGresult *res;
61     int ret;
62
63     off = 0;
64     soff = 0;
65     for (i=0;0 != params[i].num_params;i++)
66     {
67       const struct GNUNET_PQ_QueryParam *x = &params[i];
68
69       ret = x->conv (x->conv_cls,
70                      x->data,
71                      x->size,
72                      &param_values[off],
73                      &param_lengths[off],
74                      &param_formats[off],
75                      x->num_params,
76                      &scratch[soff],
77                      len - soff);
78       if (ret < 0)
79       {
80         for (off = 0; off < soff; off++)
81           GNUNET_free (scratch[off]);
82         return NULL;
83       }
84       soff += ret;
85       off += x->num_params;
86     }
87     GNUNET_assert (off == len);
88     res = PQexecPrepared (db_conn,
89                           name,
90                           len,
91                           (const char **) param_values,
92                           param_lengths,
93                           param_formats,
94                           1);
95     for (off = 0; off < soff; off++)
96       GNUNET_free (scratch[off]);
97     return res;
98   }
99 }
100
101
102 /**
103  * Free all memory that was allocated in @a rs during
104  * #GNUNET_PQ_extract_result().
105  *
106  * @param rs reult specification to clean up
107  */
108 void
109 GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs)
110 {
111   unsigned int i;
112
113   for (i=0; NULL != rs[i].conv; i++)
114     if (NULL != rs[i].cleaner)
115       rs[i].cleaner (rs[i].cls,
116                      rs[i].dst);
117 }
118
119
120 /**
121  * Extract results from a query result according to the given
122  * specification.  If colums are NULL, the destination is not
123  * modified, and #GNUNET_NO is returned.
124  *
125  * @param result result to process
126  * @param[in,out] rs result specification to extract for
127  * @param row row from the result to extract
128  * @return
129  *   #GNUNET_YES if all results could be extracted
130  *   #GNUNET_NO if at least one result was NULL
131  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
132  */
133 int
134 GNUNET_PQ_extract_result (PGresult *result,
135                           struct GNUNET_PQ_ResultSpec *rs,
136                           int row)
137 {
138   unsigned int i;
139   int had_null = GNUNET_NO;
140   int ret;
141
142   for (i=0; NULL != rs[i].conv; i++)
143   {
144     struct GNUNET_PQ_ResultSpec *spec;
145
146     spec = &rs[i];
147     ret = spec->conv (spec->cls,
148                       result,
149                       row,
150                       spec->fname,
151                       &spec->dst_size,
152                       spec->dst);
153     if (GNUNET_SYSERR == ret)
154       return GNUNET_SYSERR;
155     if (GNUNET_NO == ret)
156     {
157       had_null = GNUNET_YES;
158       continue;
159     }
160     if (NULL != spec->result_size)
161       *spec->result_size = spec->dst_size;
162   }
163   if (GNUNET_YES == had_null)
164     return GNUNET_NO;
165   return GNUNET_OK;
166 }
167
168
169 /* end of pq/pq.c */