OpenDNSSEC-enforcer 1.3.0
/build/buildd/opendnssec-1.3.0/enforcer/ksm/database_support_lite.c
Go to the documentation of this file.
00001 /*
00002  * $Id: database_support_lite.c 5320 2011-07-12 10:42:26Z jakob $
00003  *
00004  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00021  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00023  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00024  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  *
00027  */
00028 
00029 /*+
00030  * database_support - Database Utility Functions
00031  *
00032  * Description:
00033  *      Holds miscellaneous utility functions associated with the MySql
00034  *      database.
00035 -*/
00036 
00037 #include <stdarg.h>
00038 #include <string.h>
00039 #include <stdio.h>
00040 #include <time.h>
00041 
00042 #include <sqlite3.h>
00043 
00044 #include "ksm/dbsdef.h"
00045 #include "ksm/database.h"
00046 #include "ksm/debug.h"
00047 #include "ksm/message.h"
00048 #include "ksm/string_util.h"
00049 #include "ksm/string_util2.h"
00050 
00051 #define MIN(x, y) ((x) < (y) ? (x) : (y))
00052 #define MAX(x, y) ((x) > (y) ? (x) : (y))
00053 
00054 
00055 
00056 /*+
00057  * DbExecuteSqlNoResult - Execute SQL Statement and Ignore Result
00058  *
00059  * Description:
00060  *      Executes the given SQL statement; any results are discarded.
00061  *
00062  *      This function is useful for statements such as DELETE and INSERT.
00063  *
00064  * Arguments:
00065  *      DB_HANDLE handle
00066  *          Handle to the currently opened database.
00067  *
00068  *      const char* stmt_str
00069  *          Statement to execute
00070  *
00071  * Returns:
00072  *      int
00073  *          Status return.
00074  *              0               Success
00075  *              Other   Error. A message will have been output.
00076 -*/
00077 
00078 int DbExecuteSqlNoResult(DB_HANDLE handle, const char* stmt_str)
00079 {
00080     DB_RESULT   result;     /* Pointer to result string */
00081     int         status;     /* Status return */
00082 
00083     status = DbExecuteSql(handle, stmt_str, &result);
00084     if (status == 0) {
00085         if (result) {
00086 
00087             /* Result given - get rid of it, we don't want it */
00088 
00089             status = MsgLog(DBS_UNEXRES, stmt_str);
00090             DbFreeResult(result);
00091         }
00092     }
00093 
00094     return status;
00095 }
00096 
00097 
00098 /*+
00099  * DbRowId - Return ID of Current Row
00100  *
00101  * Description:
00102  *              Returns the ID of the current row.  This is assumed to be an auto-
00103  *              increment column at index 0 of the table.
00104  *
00105  * Arguments:
00106  *              DB_ROW row
00107  *                      Row in question.
00108  *
00109  *              DB_ID* id
00110  *                      ID of the row is returned here.
00111  *
00112  * Returns:
00113  *              int
00114  *                      Status return.
00115  *
00116  *                              0               Success
00117  *                              Other   Error.  A message will have been output.
00118 -*/
00119 
00120 int DbRowId(DB_ROW row, DB_ID* id)
00121 {
00122         unsigned long   rowid;          /* ID of the row as a known type */
00123         int                             status;         /* Status return */
00124 
00125     if (id == NULL) {
00126         status = MsgLog(DBS_INVARG, "NULL id");
00127         return -1;
00128     }
00129 
00130         status = DbUnsignedLong(row, 0, &rowid);
00131         *id = (DB_ID) rowid;            /* Do the conversion between types here */
00132 
00133         return status;
00134 }
00135         
00136 
00137 
00138 
00139 /*+
00140  * DbInt - Return Integer from Field
00141  *
00142  * Description:
00143  *              Returns an integer value from the current row.
00144  *
00145  * Arguments:
00146  *      DB_ROW row
00147  *          Pointer to the row object.
00148  *
00149  *      int field_index
00150  *          Index of the value required.
00151  *
00152  *      int *value
00153  *              Value returned.
00154  *
00155  * Returns:
00156  *      int
00157  *              Status return:
00158  *                      0               Success
00159  *                      Other   Error accessing data.  A message will have been output.
00160 -*/
00161 
00162 int DbInt(DB_ROW row, int field_index, int *value)
00163 {
00164     char*   buffer = NULL;              /* Text buffer for returned string */
00165         int             status;                 /* Status return */
00166 
00167         /* Access the text in the field */
00168 
00169     status = DbString(row, field_index, &buffer);
00170         if (status == 0) {
00171 
00172                 /* Got the string, can we convert it? */
00173 
00174                 if (buffer != NULL) {
00175 
00176                         /* Not best-efforts - ignore trailing non-numeric values */
00177 
00178                         status = StrStrtoi(buffer, value);
00179                         if (status == -1) {
00180 
00181                                 /* Could not translate the string to an integer */
00182 
00183                                 status = MsgLog(DBS_NOTINT, buffer);
00184                                 *value = 0;
00185                         }
00186                         DbStringFree(buffer);
00187                 }
00188                 else {
00189 
00190                         /* Field is NULL, return 0 */
00191             /* TODO should we do something better here ? */
00192 
00193                         *value = 0;
00194                 }
00195         }
00196 
00197     return status;
00198 }
00199 
00200 
00201 
00202 /*+
00203  * DbUnsignedLong - Return Unsigned Long from Field
00204  *
00205  * Description:
00206  *              Returns an integer value from the current row.
00207  *
00208  * Arguments:
00209  *      DB_ROW row
00210  *          Pointer to the row object.
00211  *
00212  *      int field_index
00213  *          Index of the value required.
00214  *
00215  *      unsigned long *value
00216  *              Value returned.
00217  *
00218  * Returns:
00219  *      int
00220  *              Status return:
00221  *                      0               Success
00222  *                      Other   Error accessing data.  A message will have been output.
00223 -*/
00224 
00225 int DbUnsignedLong(DB_ROW row, int field_index, unsigned long *value)
00226 {
00227     char*   buffer = NULL;              /* Text buffer for returned string */
00228         int             status;         /* Status return */
00229 
00230         /* Access the text in the field */
00231 
00232     status = DbString(row, field_index, &buffer);
00233         if (status == 0) {
00234 
00235                 /* Got the string, can we convert it? */
00236 
00237                 if (buffer != NULL) {
00238 
00239                         /* Not best-efforts - ignore trailing non-numeric values */
00240 
00241                         status = StrStrtoul(buffer, value);
00242                         if (status == -1) {
00243 
00244                                 /* Could not translate the string to an unsigned long */
00245 
00246                                 status = MsgLog(DBS_NOTINT, buffer);
00247                                 *value = 0;
00248                         }
00249                         DbStringFree(buffer);
00250                 }
00251                 else {
00252 
00253                         /* Field is NULL, return 0 */
00254 
00255                         *value = 0;
00256                 }
00257         }
00258 
00259     return status;
00260 }
00261 
00262 
00263 
00264 /*+
00265  * DbIntQuery - Perform Query Returning Single Integer
00266  *
00267  * Description:
00268  *      Many queries are of the form:
00269  *
00270  *          SELECT COUNT(*) FROM ...
00271  *      or
00272  *          SELECT <single integer value> FROM ...
00273  *
00274  *      This function performs the query and returns the single value.
00275  *
00276  * Arguments:
00277  *      DB_HANDLE handle
00278  *          Handle to the currently opened database.
00279  *
00280  *      int* value
00281  *          Result of the query.  Note that if the query returns no rows,
00282  *          a zero is returned.
00283  *
00284  *      const char* query
00285  *          Query to run.
00286  *
00287  * Returns:
00288  *      int
00289  *          0           Success
00290  *          Other       Error (a message will have been output)
00291 -*/
00292 
00293 int DbIntQuery(DB_HANDLE handle, int* value, const char* query)
00294 {
00295         DB_RESULT       result;         /* Result object */
00296         DB_ROW          row = NULL; /* Row object */
00297     int                 status;         /* Status return */
00298 
00299     status = DbExecuteSql(handle, query, &result);
00300     if (status == SQLITE_OK) {
00301 
00302         /* Get first row */
00303         status = DbFetchRow(result, &row);
00304                 if (status == 0) {
00305             /* Got the row, so convert to integer */
00306 
00307             status = DbInt(row, 0, value);
00308 
00309                         /* Query succeeded, but are there any more rows? */
00310                 if (DbFetchRow(result, &row) != -1) {
00311                 (void) MsgLog(DBS_TOOMANYROW, query);   /* Too much data */
00312                 }
00313 
00314         }
00315         else 
00316         {
00317                         status = MsgLog(DBS_NORESULT);  /* Query did not return a result */
00318         }
00319 
00320                 DbFreeResult(result);
00321                 DbFreeRow(row);
00322 
00323     }
00324 
00325     return status;
00326 }
00327 
00328 
00329 /*+
00330  * DbStringBuffer - Return String Value into User-Supplied Buffer
00331  *
00332  * Description:
00333  *      Returns string value from the current row into a user-supplied
00334  *      buffer.  The returned value is truncated if required.
00335  *
00336  * Arguments:
00337  *      DB_ROW row
00338  *          Pointer to the row object.
00339  *
00340  *      int field_index
00341  *          Index of the value required.
00342  *
00343  *      char* buffer
00344  *          Null-terminated buffer into which the data is put.  If the returned
00345  *          string is NULL, the buffer will contain a zero-length string.  There
00346  *          is no way to distinguish between this and the database holding an
00347  *          empty string.
00348  *
00349  *      size_t buflen
00350  *          Length of the buffer.
00351  *
00352  * Returns:
00353  *              int
00354  *                      0               Success
00355  *                      Other   Error.  A message will have been output.
00356 -*/
00357 
00358 int DbStringBuffer(DB_ROW row, int field_index, char* buffer, size_t buflen)
00359 {
00360         char*   data = NULL;    /* Data returned from DbString */
00361         int             status;             /* Status return */
00362 
00363         if (row && (row->magic == DB_ROW_MAGIC) && buffer && (buflen != 0)) {
00364 
00365                 /* Arguments OK, get the information */
00366 
00367                 status = DbString(row, field_index, &data);
00368                 if (status == 0) {
00369 
00370             /* Success, copy the data into destination & free buffer 
00371                Note the StrStrncpy copes with data == NULL */
00372 
00373             StrStrncpy(buffer, data, buflen);
00374             DbStringFree(data);
00375                 }
00376         }
00377         else {
00378 
00379                 /* Invalid srguments, notify the user */
00380 
00381                 status = MsgLog(DBS_INVARG, "DbStringBuffer");
00382         }
00383 
00384         return status;
00385 }
00386 
00387 
00388 
00389 /*+
00390  * DbErrno - Return Last Error Number
00391  *
00392  * Description:
00393  *              Returns the numeric code associated with the last operation
00394  *              on this connection that gave an error.
00395  *
00396  * Arguments:
00397  *      DB_HANDLE handle
00398  *          Handle to an open database.
00399  *
00400  * Returns:
00401  *              int
00402  *                      Error number.
00403 -*/
00404 
00405 int DbErrno(DB_HANDLE handle)
00406 {
00407     return sqlite3_errcode((sqlite3*) handle);
00408 }
00409 
00410 
00411 
00412 /*+
00413  * DbErrmsg - Return Last Error Message
00414  *
00415  * Description:
00416  *      Returns the last error on this connection.  This is just an
00417  *      encapsulation of mysql_error.
00418  *
00419  * Arguments:
00420  *      DB_HANDLE handle
00421  *          Handle to an open database.
00422  *
00423  * Returns:
00424  *      const char*
00425  *          Error string.  This should be copied and must not be freed.
00426 -*/
00427 
00428 const char* DbErrmsg(DB_HANDLE handle)
00429 {
00430     return sqlite3_errmsg((sqlite3*) handle);
00431 }
00432 
00433 
00434 /*+
00435  * DbLastRowId - Return Last Row ID
00436  *
00437  * Description:
00438  *              Returns the ID field of the last row inserted.
00439  *
00440  *              All tables are assumed to include an auto-incrementing ID field.  Apart
00441  *              from providing the unique primary key, this is a relatively
00442  *              implementation-unique way of uniquely identifying a row in a table.
00443  *
00444  * Arguments:
00445  *              DB_HANDLE handle
00446  *                      Handle to the database connection.
00447  *
00448  *              DB_ID* id
00449  *                      ID of the last row inserted (into any table) on this connection.
00450  *
00451  * Returns:
00452  *              int
00453  *                      Status return
00454  *
00455  *                              0               Success
00456  *                              Other   Error code.  An error message will have been output.
00457 -*/
00458 
00459 int DbLastRowId(DB_HANDLE handle, DB_ID* id)
00460 {
00461 
00462     if (id == NULL) {
00463         return MsgLog(DBS_INVARG, "NULL id");
00464     }
00465 
00466     /* TODO returns a sqlite_int64; can this be cast into an unsigned long?
00467      * do we need to check this for each platform? */
00468         *id = (DB_ID) sqlite3_last_insert_rowid((sqlite3*) handle);
00469 
00470         /*
00471          * In sqlite, there is no error code; a value of 0 is returned if there
00472          * is no matching row.  In this case, convert it to an error code.
00473          */
00474 
00475         return (*id != 0) ? 0 : DBS_NOSUCHROW;
00476 }