Move type check after initialization to make compiler happy
[oweals/gnunet.git] / src / postgres / postgres.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2009, 2010, 2012 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 postgres/postgres.c
22  * @brief library to help with access to a Postgres database
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_postgres_lib.h"
27
28
29 /**
30  * Check if the result obtained from Postgres has
31  * the desired status code.  If not, log an error, clear the
32  * result and return GNUNET_SYSERR.
33  *
34  * @param dbh database handle
35  * @param ret return value from database operation to check
36  * @param expected_status desired status
37  * @param command description of the command that was run
38  * @param args arguments given to the command
39  * @param filename name of the source file where the command was run
40  * @param line line number in the source file
41  * @return #GNUNET_OK if the result is acceptable
42  */
43 int
44 GNUNET_POSTGRES_check_result_ (PGconn *dbh,
45                                PGresult *ret,
46                                int expected_status,
47                                const char *command,
48                                const char *args,
49                                const char *filename,
50                                int line)
51 {
52   if (ret == NULL)
53   {
54     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
55                      "postgres",
56                      "Postgres failed to allocate result for `%s:%s' at %s:%d\n",
57                      command,
58                      args,
59                      filename,
60                      line);
61     return GNUNET_SYSERR;
62   }
63   if (PQresultStatus (ret) != expected_status)
64   {
65     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
66                      "postgres",
67                      _("`%s:%s' failed at %s:%d with error: %s\n"),
68                      command,
69                      args,
70                      filename,
71                      line,
72                      PQerrorMessage (dbh));
73     PQclear (ret);
74     return GNUNET_SYSERR;
75   }
76   return GNUNET_OK;
77 }
78
79
80 /**
81  * Run simple SQL statement (without results).
82  *
83  * @param dbh database handle
84  * @param sql statement to run
85  * @param filename filename for error reporting
86  * @param line code line for error reporting
87  * @return #GNUNET_OK on success
88  */
89 int
90 GNUNET_POSTGRES_exec_ (PGconn * dbh,
91                        const char *sql,
92                        const char *filename,
93                        int line)
94 {
95   PGresult *ret;
96
97   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
98               "Executing SQL statement `%s' at %s:%d\n",
99               sql,
100               filename,
101               line);
102   ret = PQexec (dbh,
103                 sql);
104   if (GNUNET_OK !=
105       GNUNET_POSTGRES_check_result_ (dbh,
106                                      ret,
107                                      PGRES_COMMAND_OK,
108                                      "PQexec",
109                                      sql,
110                                      filename,
111                                      line))
112     return GNUNET_SYSERR;
113   PQclear (ret);
114   return GNUNET_OK;
115 }
116
117
118 /**
119  * Prepare SQL statement.
120  *
121  * @param dbh database handle
122  * @param name name for the prepared SQL statement
123  * @param sql SQL code to prepare
124  * @param nparams number of parameters in sql
125  * @param filename filename for error reporting
126  * @param line code line for error reporting
127  * @return #GNUNET_OK on success
128  */
129 int
130 GNUNET_POSTGRES_prepare_ (PGconn *dbh,
131                           const char *name,
132                           const char *sql,
133                           int nparams,
134                           const char *filename,
135                           int line)
136 {
137   PGresult *ret;
138
139   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
140               "Preparing SQL statement `%s' as `%s' at %s:%d\n",
141               sql,
142               name,
143               filename,
144               line);
145   ret = PQprepare (dbh,
146                    name,
147                    sql,
148                    nparams, NULL);
149   if (GNUNET_OK !=
150       GNUNET_POSTGRES_check_result_ (dbh,
151                                      ret,
152                                      PGRES_COMMAND_OK,
153                                      "PQprepare",
154                                      sql,
155                                      filename,
156                                      line))
157     return GNUNET_SYSERR;
158   PQclear (ret);
159   return GNUNET_OK;
160 }
161
162
163 /**
164  * Connect to a postgres database
165  *
166  * @param cfg configuration
167  * @param section configuration section to use to get Postgres configuration options
168  * @return the postgres handle
169  */
170 PGconn *
171 GNUNET_POSTGRES_connect (const struct GNUNET_CONFIGURATION_Handle * cfg,
172                          const char *section)
173 {
174   PGconn *dbh;
175   char *conninfo;
176
177   /* Open database and precompile statements */
178   if (GNUNET_OK !=
179       GNUNET_CONFIGURATION_get_value_string (cfg,
180                                              section,
181                                              "CONFIG",
182                                              &conninfo))
183     conninfo = NULL;
184   dbh = PQconnectdb (conninfo == NULL ? "" : conninfo);
185   GNUNET_free_non_null (conninfo);
186   if (NULL == dbh)
187   {
188     /* FIXME: warn about out-of-memory? */
189     return NULL;
190   }
191   if (PQstatus (dbh) != CONNECTION_OK)
192   {
193     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
194                      "postgres",
195                      _("Unable to initialize Postgres: %s\n"),
196                      PQerrorMessage (dbh));
197     PQfinish (dbh);
198     return NULL;
199   }
200   return dbh;
201 }
202
203
204 /**
205  * Delete the row identified by the given rowid (qid
206  * in postgres).
207  *
208  * @param dbh database handle
209  * @param stmt name of the prepared statement
210  * @param rowid which row to delete
211  * @return #GNUNET_OK on success
212  */
213 int
214 GNUNET_POSTGRES_delete_by_rowid (PGconn * dbh,
215                                  const char *stmt,
216                                  uint32_t rowid)
217 {
218   uint32_t brow = htonl (rowid);
219   const char *paramValues[] = { (const char *) &brow };
220   int paramLengths[] = { sizeof (brow) };
221   const int paramFormats[] = { 1 };
222   PGresult *ret;
223
224   ret = PQexecPrepared (dbh,
225                         stmt,
226                         1,
227                         paramValues,
228                         paramLengths,
229                         paramFormats,
230                         1);
231   if (GNUNET_OK !=
232       GNUNET_POSTGRES_check_result_ (dbh, ret,
233                                      PGRES_COMMAND_OK,
234                                      "PQexecPrepared",
235                                      "delrow",
236                                      __FILE__,
237                                      __LINE__))
238   {
239     return GNUNET_SYSERR;
240   }
241   PQclear (ret);
242   return GNUNET_OK;
243 }
244
245
246 /* end of postgres.c */