OpenDNSSEC-enforcer  1.3.14
database_access_mysql.c
Go to the documentation of this file.
1 /*
2  * $Id: database_access_mysql.c 2676 2010-01-11 15:31:31Z sion $
3  *
4  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 /*+
30  * database_access - database Access Functions
31  *
32  * Description:
33  * Holds miscellaneous utility functions associated with the MySql
34  * database.
35  *
36  * This particular file holds encapsulations of the underlying access
37  * functions - querying/modifying the database and retrieving results.
38 -*/
39 
40 #include <stdarg.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <time.h>
44 
45 #include <mysql.h>
46 
47 #include "ksm/dbsdef.h"
48 #include "ksm/database.h"
49 #include "ksm/debug.h"
50 #include "ksm/memory.h"
51 #include "ksm/message.h"
52 #include "ksm/string_util.h"
53 
54 #define MIN(x, y) ((x) < (y) ? (x) : (y))
55 #define MAX(x, y) ((x) > (y) ? (x) : (y))
56 
57 
58 /*+
59  * DbExecuteSqlStatement - Execute SQL Statement
60  *
61  * Description:
62  * A wrapper round mysql_query that outputs the query being executed
63  * if the appropriate debug flag is set.
64  *
65  * Arguments:
66  * DB_HANDLE handle
67  * Handle to the currently opened database.
68  *
69  * const char* stmt_str
70  * SQL statement to execute.
71  *
72  * Returns:
73  * int
74  * Any return value from mysql_query.
75 -*/
76 
77 static int DbExecuteSqlStatement(DB_HANDLE handle, const char* stmt_str)
78 {
79  DbgOutput(DBG_M_SQL, "%s\n", stmt_str);
80  return mysql_query((MYSQL*) handle, stmt_str);
81 }
82 
83 
84 
85 /*+
86  * DbExecuteSql - Execute SQL Statement
87  *
88  * Description:
89  * Executes the given SQL statement and returns the results (if any).
90  *
91  * Arguments:
92  * DB_HANDLE handle
93  * Handle to the currently opened database.
94  *
95  * const char* stmt_str
96  * Statement to execute.
97  *
98  * DB_RESULT* result
99  * Pointer to the result set is put here. It must be freed by
100  * DbFreeResult(). This is NULL if no data is returned; on error, the
101  * value is undefined.
102  *
103  * Returns:
104  * int
105  * 0 Success
106  * Other Error code. A message will have been output.
107 -*/
108 
109 int DbExecuteSql(DB_HANDLE handle, const char* stmt_str, DB_RESULT* result)
110 {
111  const char* errmsg = NULL; /* Error message from MySql on failure */
112  int status = 0; /* Status return */
113 
114  /* Argument check */
115 
116  if ((!handle) || (!stmt_str) || (*stmt_str == '\0') || (! result)) {
117  status = MsgLog(DBS_INVARG, "DbExecuteSql");
118  return status;
119  }
120 
121  /* Allocate the result structure */
122 
123  *result = (DB_RESULT) MemCalloc(1, sizeof(struct db_result));
124  (*result)->magic = DB_RESULT_MAGIC;
125  (*result)->handle = handle;
126 
127  /* Execute statement */
128 
129  status = DbExecuteSqlStatement(handle, stmt_str);
130  if (status == 0) {
131 
132  /* Get the pointer to the result set */
133 
134  (*result)->data = mysql_store_result((MYSQL*) handle);
135  if ((*result)->data == NULL) {
136 
137  /*
138  * No result set, so could be some error. See if this is the case
139  * by checking if there is error text. If not, there are no results
140  * from the SQL - it could have been a statement such as DELETE or
141  * INSERT.
142  */
143 
144  errmsg = DbErrmsg(handle);
145  if (errmsg && *errmsg) {
146 
147  /* Error text, so error occurred. Output message & tidy up */
148 
149  status = MsgLog(DBS_SQLFAIL, errmsg);
150  }
151  /*
152  * else {
153  *
154  * No error, so we just don't have any results.
155  * }
156  */
157 
158  /*
159  * Regardless of what heppened, there is no result set, so free up
160  * allocated memory.
161  */
162 
163  MemFree(*result);
164  *result = NULL;
165  }
166  else {
167 
168  /*
169  * Success. "result" holds the result set. Store the number of
170  * fields along with the length of each one for possible later use.
171  */
172 
173  (*result)->count = mysql_field_count((MYSQL*) (*result)->handle);
174  }
175  }
176  else {
177 
178  /* Query failed. Log the error and free up the structure */
179 
180  status = MsgLog(DBS_SQLFAIL, DbErrmsg(handle));
181  MemFree(*result);
182  *result = NULL;
183  }
184 
185  return status;
186 }
187 
188 /*+
189  * DbFreeResult - Free Result
190  *
191  * Description:
192  * Frees up resources allocated for the result by DbExecuteSql.
193  *
194  * Arguments:
195  * DB_RESULT result
196  * Handle to the query result. May be NULL, in which case this
197  * function is a no-op.
198  *
199  * If invalid, an error message will be output.
200 -*/
201 
203 {
204  if (result) {
205  if (result->magic == DB_RESULT_MAGIC) {
206 
207  /* Free up data */
208 
209  mysql_free_result((MYSQL_RES*) result->data);
210  MemFree(result);
211  }
212  else {
213 
214  /* Invalid structure - output a warning but do nothing */
215 
216  (void) MsgLog(DBS_INVARG, "DbFreeResult");
217  }
218  }
219 
220  return;
221 }
222 
223 
224 
225 /*+
226  * DbFetchRow - Fetch Row from Result
227  *
228  * Description:
229  * Fetches the next row from the result set. The structure returned
230  * *must* be freed by DbFreeRow() after use.
231  *
232  * Arguments:
233  * DB_RESULT result
234  * The result handle returned by the call to DbExecuteSql.
235  *
236  * DB_ROW* row
237  * The row object is put here. It will be NULL end of file; on error,
238  * it is undefined.
239  *
240  * Returns:
241  * int
242  * 0 Success, row information returned
243  * -1 Success, no more rows for this result
244  * Other Error code or error number from DbErrno().
245 -*/
246 
247 int DbFetchRow(DB_RESULT result, DB_ROW* row)
248 {
249  int status = 0; /* Status return */
250  MYSQL_ROW rowdata; /* Fetched row information */
251 
252  if (result && (result->magic == DB_RESULT_MAGIC) && row) {
253 
254  /* There is a result structure (and row pointer), do something */
255 
256  rowdata = mysql_fetch_row(result->data);
257  if (rowdata) {
258 
259  /* Something returned, encapsulate the result in a structure */
260 
261  *row = (DB_ROW) MemCalloc(1, sizeof(struct db_row));
262  (*row)->magic = DB_ROW_MAGIC;
263  (*row)->result = result;
264  (*row)->data = rowdata;
265  }
266  else {
267 
268  /*
269  * End of file - in this implementation, only mysql_store_result is
270  * used, so mysql_fetch_row returns NULL only on end of file.
271  */
272 
273  /* leave freeing the row to the calling function */
274  /* *row = NULL; */
275  status = -1;
276  }
277  }
278  else {
279  status = MsgLog(DBS_INVARG, "DbFetchRow");
280  }
281 
282  return status;
283 }
284 
285 
286 
287 /*+
288  * DbFreeRow - Free Row
289  *
290  * Description:
291  * Frees up resources allocated for the row.
292  *
293  * Arguments:
294  * DB_RESULT result
295  * Handle to the query result. May be NULL, in which case this
296  * function is a no-op.
297 -*/
298 
299 void DbFreeRow(DB_ROW row)
300 {
301  if (row) {
302  if (row->magic == DB_ROW_MAGIC) {
303  MemFree(row);
304  }
305  else {
306 
307  /* Output warning, but otherwise do nothing */
308 
309  (void) MsgLog(DBS_INVARG, "DbFreeRow");
310  }
311  }
312 
313  return;
314 }
315 
316 
317 
318 /*+
319  * DbString - Return String Value
320  *
321  * Description:
322  * Returns string value from the current row.
323  *
324  * Arguments:
325  * DB_ROW row
326  * Pointer to the row object.
327  *
328  * int field_index
329  * Index of the value required.
330  *
331  * char** result
332  * Value of the field. It is up to the caller to free it with
333  * a call to DbStringFree(). Note that this can be NULL if the
334  * corresponding field is NULL.
335  *
336  * Returns:
337  * int
338  * 0 Success
339  * Other Some error. A message will have been output
340 -*/
341 
342 int DbString(DB_ROW row, int field_index, char** result)
343 {
344  int status = 0; /* Status return */
345  unsigned long *lengths; /* Lengths of columns in each row */
346 
347  /* Check arguments */
348 
349  if (row && (row->magic == DB_ROW_MAGIC) && result) {
350 
351  /* Is the index requested valid? */
352 
353  if ((field_index >= 0) && (field_index < row->result->count)) {
354 
355  /* Get the lengths of the fields in the row */
356 
357  lengths = mysql_fetch_lengths((MYSQL_RES*) row->result->data);
358 
359  /* Get string into null-terminated form */
360 
361  if (row->data[field_index] != NULL) {
362  /* TODO replece the below with strdup or StrStrdup ? */
363  *result = MemMalloc(lengths[field_index] + 1);
364  memcpy(*result, row->data[field_index], lengths[field_index]);
365  (*result)[lengths[field_index]] = 0;
366  }
367  else {
368  *result = NULL;
369  }
370  }
371  else {
372 
373  /* Invalid field, tell the user */
374 
375  status = MsgLog(DBS_INVINDEX, field_index, row->result->count);
376  }
377 
378  }
379  else {
380 
381  /* Problem with the command arguments */
382 
383  status = MsgLog(DBS_INVARG, "DbString");
384  }
385 
386  return status;
387 
388 }
389 
390 
391 /*+
392  * DbStringFree - Free String Returned by DbString
393  *
394  * Description:
395  * Frees the pointer-to string.
396  *
397  * Arguments:
398  * char* string
399  * String allocated by DbString. On exit, this pointer is invalid.
400 -*/
401 
402 void DbStringFree(char* string)
403 {
404  MemFree(string);
405 }
406 
407 /*+
408  * DbBeginTransaction - Start a (non-nested) transaction
409  *
410  * Description:
411  * NB the following will not work if your tables are MyISAM
412  * as transactions are not supported
413  *
414  * Arguments:
415  * NONE
416 -*/
417 
419 {
420  const char* sql = "start transaction";
421  return DbExecuteSqlNoResult(DbHandle(), sql);
422 }
423 
424 /*+
425  * DbCommit - End a (non-nested) transaction by commiting it
426  *
427  * Description:
428  *
429  *
430  * Arguments:
431  * NONE
432 -*/
433 
434 int DbCommit(void)
435 {
436  const char* sql = "commit";
437  return DbExecuteSqlNoResult(DbHandle(), sql);
438 }
439 
440 /*+
441  * DbRollback - End a (non-nested) transaction by rolling it back
442  *
443  * Description:
444  *
445  *
446  * Arguments:
447  * NONE
448 -*/
449 
450 int DbRollback(void)
451 {
452  const char* sql = "rollback";
453  return DbExecuteSqlNoResult(DbHandle(), sql);
454 }