-fix misc issues
[oweals/gnunet.git] / src / my / my.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2016 Inria & GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file my/my.c
22  * @brief library to help with access to a MySQL database
23  * @author Christophe Genevey
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include <mysql/mysql.h>
28 #include "gnunet_my_lib.h"
29
30 #define STRING_SIZE 50
31
32 /**
33  * Run a prepared SELECT statement.
34  *
35  * @param mc mysql context
36  * @param sh handle to SELECT statment
37  * @param params parameters to the statement
38  * @return
39       #GNUNET_YES if we can prepare all statement
40       #GNUNET_SYSERR if we can't prepare all statement
41  */
42 int
43 GNUNET_MY_exec_prepared (struct GNUNET_MYSQL_Context *mc,
44                          struct GNUNET_MYSQL_StatementHandle *sh,
45                          const struct GNUNET_MY_QueryParam *params)
46 {
47   const struct GNUNET_MY_QueryParam *p;
48   unsigned int num;
49   unsigned int i;
50   MYSQL_STMT *stmt;
51
52   num = 0;
53   for (i=0;NULL != params[i].conv;i++)
54     num += params[i].num_params;
55   {
56     MYSQL_BIND qbind[num];
57     unsigned int off;
58
59     memset(qbind, 0, sizeof(qbind));
60     off = 0;
61     for (i=0;NULL != (p = &params[i])->conv;i++)
62     {
63       if (GNUNET_OK !=
64           p->conv (p->conv_cls,
65                    p,
66                    &qbind[off]))
67       {
68         return GNUNET_SYSERR;
69       }
70       off += p->num_params;
71     }
72     stmt = GNUNET_MYSQL_statement_get_stmt (mc, sh);
73     if (mysql_stmt_bind_param (stmt,
74                                qbind))
75     {
76       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql",
77                        _("`%s' failed at %s:%d with error: %s\n"),
78                        "mysql_stmt_bind_param", __FILE__, __LINE__,
79                        mysql_stmt_error (stmt));
80       GNUNET_MYSQL_statements_invalidate (mc);
81       return GNUNET_SYSERR;
82     }
83
84     if (mysql_stmt_execute (stmt))
85     {
86       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql",
87                        _("`%s' failed at %s:%d with error: %s\n"),
88                        "mysql_stmt_execute", __FILE__, __LINE__,
89                        mysql_stmt_error (stmt));
90       GNUNET_MYSQL_statements_invalidate (mc);
91       return GNUNET_SYSERR;
92     }
93   }
94
95   return GNUNET_OK;
96 }
97
98
99 /**
100  * Extract results from a query result according to the given
101  * specification.  Always fetches the next row.
102  *
103  *
104  * @param sh statement that returned results
105  * @param rs specification to extract for
106  * @return
107  *  #GNUNET_YES if all results could be extracted
108  *  #GNUNET_NO if there is no more data in the result set
109  *  #GNUNET_SYSERR if a result was invalid
110  */
111 int
112 GNUNET_MY_extract_result (struct GNUNET_MYSQL_StatementHandle *sh,
113                           struct GNUNET_MY_ResultSpec *rs)
114 {
115   unsigned int num_fields;
116   unsigned int i;
117   int ret;
118   MYSQL_STMT *stmt;
119
120   stmt = GNUNET_MYSQL_statement_get_stmt (NULL /* FIXME */, sh);
121   if (NULL == stmt)
122   {
123     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql",
124                     ("`%s' failed at %s:%d with error: %s\n"),
125                        "mysql_stmt_bind_result", __FILE__, __LINE__,
126                        mysql_stmt_error (stmt));
127     return GNUNET_SYSERR;
128   }
129
130   num_fields = 0;
131   for (i=0;NULL != rs[i].pre_conv;i++)
132     num_fields += rs[i].num_fields;
133
134   if (mysql_stmt_field_count (stmt) != num_fields)
135   {
136     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
137                 "Number of fields missmatch between SQL result and result specification\n");
138     return GNUNET_SYSERR;
139   }
140
141   {
142     MYSQL_BIND result[num_fields];
143     unsigned int field_off;
144
145     memset (result, 0, sizeof (MYSQL_BIND) * num_fields);
146     field_off = 0;
147     for (i=0;NULL != rs[i].pre_conv;i++)
148     {
149       struct GNUNET_MY_ResultSpec *rp = &rs[i];
150
151       if (GNUNET_OK !=
152           rp->pre_conv (rp->conv_cls,
153                         rp,
154                         stmt,
155                         field_off,
156                         &result[field_off]))
157       {
158         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
159                     "Pre-conversion for MySQL result failed at offset %u\n",
160                     i);
161         GNUNET_MY_cleanup_result (rs);
162         return GNUNET_SYSERR;
163       }
164       field_off += rp->num_fields;
165     }
166     if (mysql_stmt_bind_result (stmt, result))
167     {
168       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
169                        "my",
170                        _("`%s' failed at %s:%d with error: %s\n"),
171                        "mysql_stmt_bind_result", __FILE__, __LINE__,
172                        mysql_stmt_error (stmt));
173       return GNUNET_SYSERR;
174     }
175
176     ret = mysql_stmt_fetch (stmt);
177
178     if (MYSQL_NO_DATA == ret)
179       return GNUNET_NO;
180     if ((0 != ret ) & (MYSQL_DATA_TRUNCATED != ret))
181     {
182       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
183                        "my",
184                        _("mysql_stmt_fetch failed at %s:%d with error: %s\n"),
185                        __FILE__, __LINE__,
186                        mysql_stmt_error (stmt));
187       return GNUNET_SYSERR;
188     }
189     field_off = 0;
190     for (i=0;NULL != rs[i].post_conv;i++)
191     {
192       struct GNUNET_MY_ResultSpec *rp = &rs[i];
193
194       if (NULL != rp->post_conv)
195         if (GNUNET_OK !=
196             rp->post_conv (rp->conv_cls,
197                            rp,
198                            stmt,
199                            field_off,
200                            &result[field_off]))
201         {
202           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
203                       "Post-conversion for MySQL result failed at offset %u\n",
204                       i);
205           GNUNET_MY_cleanup_result (rs);
206           return GNUNET_SYSERR;
207         }
208       field_off += rp->num_fields;
209     }
210   }
211   return GNUNET_OK;
212 }
213
214
215 /**
216  * Free all memory that was allocated in @a rs during
217  * #GNUNET_MY_extract_result().
218  *
219  * @param rs reult specification to clean up
220  */
221 void
222 GNUNET_MY_cleanup_result (struct GNUNET_MY_ResultSpec *rs)
223 {
224   unsigned int i;
225
226   for (i=0;NULL != rs[i].cleaner;i++)
227     rs[i].cleaner (rs[i].conv_cls,
228                    &rs[i]);
229 }
230
231
232 /* end of my.c */