OpenDNSSEC-enforcer  1.3.9
database_support_lite.c
Go to the documentation of this file.
1 /*
2  * $Id: database_support_lite.c 1285 2009-07-15 14:07:41Z 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_support - Database Utility Functions
31  *
32  * Description:
33  * Holds miscellaneous utility functions associated with the MySql
34  * database.
35 -*/
36 
37 #include <stdarg.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <time.h>
41 
42 #include <sqlite3.h>
43 
44 #include "ksm/dbsdef.h"
45 #include "ksm/database.h"
46 #include "ksm/debug.h"
47 #include "ksm/message.h"
48 #include "ksm/string_util.h"
49 #include "ksm/string_util2.h"
50 
51 #define MIN(x, y) ((x) < (y) ? (x) : (y))
52 #define MAX(x, y) ((x) > (y) ? (x) : (y))
53 
54 
55 
56 /*+
57  * DbExecuteSqlNoResult - Execute SQL Statement and Ignore Result
58  *
59  * Description:
60  * Executes the given SQL statement; any results are discarded.
61  *
62  * This function is useful for statements such as DELETE and INSERT.
63  *
64  * Arguments:
65  * DB_HANDLE handle
66  * Handle to the currently opened database.
67  *
68  * const char* stmt_str
69  * Statement to execute
70  *
71  * Returns:
72  * int
73  * Status return.
74  * 0 Success
75  * Other Error. A message will have been output.
76 -*/
77 
78 int DbExecuteSqlNoResult(DB_HANDLE handle, const char* stmt_str)
79 {
80  DB_RESULT result; /* Pointer to result string */
81  int status; /* Status return */
82 
83  status = DbExecuteSql(handle, stmt_str, &result);
84  if (status == 0) {
85  if (result) {
86 
87  /* Result given - get rid of it, we don't want it */
88 
89  status = MsgLog(DBS_UNEXRES, stmt_str);
90  DbFreeResult(result);
91  }
92  }
93 
94  return status;
95 }
96 
97 
98 /*+
99  * DbRowId - Return ID of Current Row
100  *
101  * Description:
102  * Returns the ID of the current row. This is assumed to be an auto-
103  * increment column at index 0 of the table.
104  *
105  * Arguments:
106  * DB_ROW row
107  * Row in question.
108  *
109  * DB_ID* id
110  * ID of the row is returned here.
111  *
112  * Returns:
113  * int
114  * Status return.
115  *
116  * 0 Success
117  * Other Error. A message will have been output.
118 -*/
119 
120 int DbRowId(DB_ROW row, DB_ID* id)
121 {
122  unsigned long rowid; /* ID of the row as a known type */
123  int status; /* Status return */
124 
125  if (id == NULL) {
126  status = MsgLog(DBS_INVARG, "NULL id");
127  return -1;
128  }
129 
130  status = DbUnsignedLong(row, 0, &rowid);
131  *id = (DB_ID) rowid; /* Do the conversion between types here */
132 
133  return status;
134 }
135 
136 
137 
138 
139 /*+
140  * DbInt - Return Integer from Field
141  *
142  * Description:
143  * Returns an integer value from the current row.
144  *
145  * Arguments:
146  * DB_ROW row
147  * Pointer to the row object.
148  *
149  * int field_index
150  * Index of the value required.
151  *
152  * int *value
153  * Value returned.
154  *
155  * Returns:
156  * int
157  * Status return:
158  * 0 Success
159  * Other Error accessing data. A message will have been output.
160 -*/
161 
162 int DbInt(DB_ROW row, int field_index, int *value)
163 {
164  char* buffer = NULL; /* Text buffer for returned string */
165  int status; /* Status return */
166 
167  /* Access the text in the field */
168 
169  status = DbString(row, field_index, &buffer);
170  if (status == 0) {
171 
172  /* Got the string, can we convert it? */
173 
174  if (buffer != NULL) {
175 
176  /* Not best-efforts - ignore trailing non-numeric values */
177 
178  status = StrStrtoi(buffer, value);
179  if (status == -1) {
180 
181  /* Could not translate the string to an integer */
182 
183  status = MsgLog(DBS_NOTINT, buffer);
184  *value = 0;
185  }
186  DbStringFree(buffer);
187  }
188  else {
189 
190  /* Field is NULL, return 0 */
191  /* TODO should we do something better here ? */
192 
193  *value = 0;
194  }
195  }
196 
197  return status;
198 }
199 
200 
201 
202 /*+
203  * DbUnsignedLong - Return Unsigned Long from Field
204  *
205  * Description:
206  * Returns an integer value from the current row.
207  *
208  * Arguments:
209  * DB_ROW row
210  * Pointer to the row object.
211  *
212  * int field_index
213  * Index of the value required.
214  *
215  * unsigned long *value
216  * Value returned.
217  *
218  * Returns:
219  * int
220  * Status return:
221  * 0 Success
222  * Other Error accessing data. A message will have been output.
223 -*/
224 
225 int DbUnsignedLong(DB_ROW row, int field_index, unsigned long *value)
226 {
227  char* buffer = NULL; /* Text buffer for returned string */
228  int status; /* Status return */
229 
230  /* Access the text in the field */
231 
232  status = DbString(row, field_index, &buffer);
233  if (status == 0) {
234 
235  /* Got the string, can we convert it? */
236 
237  if (buffer != NULL) {
238 
239  /* Not best-efforts - ignore trailing non-numeric values */
240 
241  status = StrStrtoul(buffer, value);
242  if (status == -1) {
243 
244  /* Could not translate the string to an unsigned long */
245 
246  status = MsgLog(DBS_NOTINT, buffer);
247  *value = 0;
248  }
249  DbStringFree(buffer);
250  }
251  else {
252 
253  /* Field is NULL, return 0 */
254 
255  *value = 0;
256  }
257  }
258 
259  return status;
260 }
261 
262 
263 
264 /*+
265  * DbIntQuery - Perform Query Returning Single Integer
266  *
267  * Description:
268  * Many queries are of the form:
269  *
270  * SELECT COUNT(*) FROM ...
271  * or
272  * SELECT <single integer value> FROM ...
273  *
274  * This function performs the query and returns the single value.
275  *
276  * Arguments:
277  * DB_HANDLE handle
278  * Handle to the currently opened database.
279  *
280  * int* value
281  * Result of the query. Note that if the query returns no rows,
282  * a zero is returned.
283  *
284  * const char* query
285  * Query to run.
286  *
287  * Returns:
288  * int
289  * 0 Success
290  * Other Error (a message will have been output)
291 -*/
292 
293 int DbIntQuery(DB_HANDLE handle, int* value, const char* query)
294 {
295  DB_RESULT result; /* Result object */
296  DB_ROW row = NULL; /* Row object */
297  int status; /* Status return */
298 
299  status = DbExecuteSql(handle, query, &result);
300  if (status == SQLITE_OK) {
301 
302  /* Get first row */
303  status = DbFetchRow(result, &row);
304  if (status == 0) {
305  /* Got the row, so convert to integer */
306 
307  status = DbInt(row, 0, value);
308 
309  /* Query succeeded, but are there any more rows? */
310  if (DbFetchRow(result, &row) != -1) {
311  (void) MsgLog(DBS_TOOMANYROW, query); /* Too much data */
312  }
313 
314  }
315  else
316  {
317  status = MsgLog(DBS_NORESULT); /* Query did not return a result */
318  }
319 
320  DbFreeResult(result);
321  DbFreeRow(row);
322 
323  }
324 
325  return status;
326 }
327 
328 
329 /*+
330  * DbStringBuffer - Return String Value into User-Supplied Buffer
331  *
332  * Description:
333  * Returns string value from the current row into a user-supplied
334  * buffer. The returned value is truncated if required.
335  *
336  * Arguments:
337  * DB_ROW row
338  * Pointer to the row object.
339  *
340  * int field_index
341  * Index of the value required.
342  *
343  * char* buffer
344  * Null-terminated buffer into which the data is put. If the returned
345  * string is NULL, the buffer will contain a zero-length string. There
346  * is no way to distinguish between this and the database holding an
347  * empty string.
348  *
349  * size_t buflen
350  * Length of the buffer.
351  *
352  * Returns:
353  * int
354  * 0 Success
355  * Other Error. A message will have been output.
356 -*/
357 
358 int DbStringBuffer(DB_ROW row, int field_index, char* buffer, size_t buflen)
359 {
360  char* data = NULL; /* Data returned from DbString */
361  int status; /* Status return */
362 
363  if (row && (row->magic == DB_ROW_MAGIC) && buffer && (buflen != 0)) {
364 
365  /* Arguments OK, get the information */
366 
367  status = DbString(row, field_index, &data);
368  if (status == 0) {
369 
370  /* Success, copy the data into destination & free buffer
371  Note the StrStrncpy copes with data == NULL */
372 
373  StrStrncpy(buffer, data, buflen);
374  DbStringFree(data);
375  }
376  }
377  else {
378 
379  /* Invalid srguments, notify the user */
380 
381  status = MsgLog(DBS_INVARG, "DbStringBuffer");
382  }
383 
384  return status;
385 }
386 
387 
388 
389 /*+
390  * DbErrno - Return Last Error Number
391  *
392  * Description:
393  * Returns the numeric code associated with the last operation
394  * on this connection that gave an error.
395  *
396  * Arguments:
397  * DB_HANDLE handle
398  * Handle to an open database.
399  *
400  * Returns:
401  * int
402  * Error number.
403 -*/
404 
405 int DbErrno(DB_HANDLE handle)
406 {
407  return sqlite3_errcode((sqlite3*) handle);
408 }
409 
410 
411 
412 /*+
413  * DbErrmsg - Return Last Error Message
414  *
415  * Description:
416  * Returns the last error on this connection. This is just an
417  * encapsulation of mysql_error.
418  *
419  * Arguments:
420  * DB_HANDLE handle
421  * Handle to an open database.
422  *
423  * Returns:
424  * const char*
425  * Error string. This should be copied and must not be freed.
426 -*/
427 
428 const char* DbErrmsg(DB_HANDLE handle)
429 {
430  return sqlite3_errmsg((sqlite3*) handle);
431 }
432 
433 
434 /*+
435  * DbLastRowId - Return Last Row ID
436  *
437  * Description:
438  * Returns the ID field of the last row inserted.
439  *
440  * All tables are assumed to include an auto-incrementing ID field. Apart
441  * from providing the unique primary key, this is a relatively
442  * implementation-unique way of uniquely identifying a row in a table.
443  *
444  * Arguments:
445  * DB_HANDLE handle
446  * Handle to the database connection.
447  *
448  * DB_ID* id
449  * ID of the last row inserted (into any table) on this connection.
450  *
451  * Returns:
452  * int
453  * Status return
454  *
455  * 0 Success
456  * Other Error code. An error message will have been output.
457 -*/
458 
459 int DbLastRowId(DB_HANDLE handle, DB_ID* id)
460 {
461 
462  if (id == NULL) {
463  return MsgLog(DBS_INVARG, "NULL id");
464  }
465 
466  /* TODO returns a sqlite_int64; can this be cast into an unsigned long?
467  * do we need to check this for each platform? */
468  *id = (DB_ID) sqlite3_last_insert_rowid((sqlite3*) handle);
469 
470  /*
471  * In sqlite, there is no error code; a value of 0 is returned if there
472  * is no matching row. In this case, convert it to an error code.
473  */
474 
475  return (*id != 0) ? 0 : DBS_NOSUCHROW;
476 }