OpenDNSSEC-enforcer  1.3.8
/build/buildd/opendnssec-1.3.8/enforcer/ksm/database_access_lite.c
Go to the documentation of this file.
00001 /*
00002  * $Id: database_access_lite.c 2676 2010-01-11 15:31:31Z sion $
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_access_lite - database Access Functions
00031  *
00032  * Description:
00033  *      Holds miscellaneous utility functions associated with the sqlite
00034  *      database.
00035  *
00036  *      This particular file holds encapsulations of the underlying access
00037  *      functions - querying/modifying the database and retrieving results.
00038 -*/
00039 
00040 #include <stdarg.h>
00041 #include <string.h>
00042 #include <stdio.h>
00043 #include <time.h>
00044 #include <unistd.h>
00045 
00046 #include <sqlite3.h>
00047 
00048 #include "ksm/dbsdef.h"
00049 #include "ksm/database.h"
00050 #include "ksm/debug.h"
00051 #include "ksm/memory.h"
00052 #include "ksm/message.h"
00053 #include "ksm/string_util.h"
00054 
00055 #define MIN(x, y) ((x) < (y) ? (x) : (y))
00056 #define MAX(x, y) ((x) > (y) ? (x) : (y))
00057 
00058 /* possible wrapper for sqlite3_step which will wait for a block to go */
00059 int sqlite3_my_step(sqlite3_stmt *pStmt)
00060 {
00061         int rc;
00062     struct timeval tv;
00063 
00064     rc = sqlite3_step(pStmt);
00065     
00066     while (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) {
00067         tv.tv_sec = 1;
00068         tv.tv_usec = 0;
00069         select(0, NULL, NULL, NULL, &tv);
00070 
00071         rc = sqlite3_step(pStmt);
00072     }
00073 
00074     return rc;
00075 
00076 }
00077 
00078 /*+
00079  * DbExecuteSqlStatement - Execute SQL Statement
00080  *
00081  * Description:
00082  *      A wrapper round sqlite3_prepare_v2 and one call to sqlite3_step
00083  *      that outputs the query being executed if the appropriate debug flag 
00084  *      is set.
00085  *
00086  * Arguments:
00087  *      DB_HANDLE handle
00088  *          Handle to the currently opened database.
00089  *
00090  *      const char* stmt_str
00091  *          SQL statement to execute.
00092  *
00093  * Returns:
00094  *      int
00095  *          Any return value from sqlite3_prepare_v2 or sqlite3_step.
00096  *          SQLITE_OK if the command executes correctly
00097 -*/
00098 
00099 static int DbExecuteSqlStatement(DB_HANDLE handle, const char* stmt_str, DB_RESULT* result)
00100 {
00101         int rc;
00102     DbgOutput(DBG_M_SQL, "%s\n", stmt_str);
00103     rc = sqlite3_prepare_v2((sqlite3*) handle, stmt_str, -1, &((*result)->data), 0);
00104         if( rc != SQLITE_OK )
00105     {
00106                 return rc;
00107         }
00108 
00109     return sqlite3_step((*result)->data);
00110 }
00111 
00112 
00113 
00114 /*+
00115  * DbExecuteSql - Execute SQL Statement
00116  *
00117  * Description:
00118  *      Executes the given SQL statement and returns the results (if any).
00119  *
00120  * Arguments:
00121  *      DB_HANDLE handle
00122  *          Handle to the currently opened database.
00123  *
00124  *      const char* stmt_str
00125  *          Statement to execute.
00126  *
00127  *      DB_RESULT* result
00128  *          Pointer to the result set is put here.  It must be freed by
00129  *          DbFreeResult().  This is NULL if no data is returned; on error, the
00130  *          value is undefined.
00131  *
00132  * Returns:
00133  *              int
00134  *                      0               Success
00135  *                      Other   Error code.  A message will have been output.
00136 -*/
00137 
00138 int DbExecuteSql(DB_HANDLE handle, const char* stmt_str, DB_RESULT* result)
00139 {
00140     const char* errmsg = NULL;  /* Error message from MySql on failure */
00141     int         status = 0;     /* Status return */
00142 
00143         /* Argument check */
00144 
00145         if ((!handle) || (!stmt_str) || (*stmt_str == '\0') || (! result)) {
00146                 status = MsgLog(DBS_INVARG, "DbExecuteSql");
00147                 return status;
00148         }
00149 
00150         /* Allocate the result structure */
00151 
00152     *result = (DB_RESULT) MemCalloc(1, sizeof(struct db_result));
00153         (*result)->magic = DB_RESULT_MAGIC;
00154         (*result)->handle = handle;
00155         (*result)->first_row = 1;
00156 
00157     /* Execute statement */
00158 
00159     status = DbExecuteSqlStatement(handle, stmt_str, result);
00160     if (status == SQLITE_ROW) {
00161                 /* Reset the status so that it is consistent across db engines */
00162                 status = 0;
00163 
00164         /* Check the pointer to the result set */
00165         if ((*result)->data == NULL) {
00166 
00167             /*
00168              * No result set, so could be some error.  See if this is the case
00169              * by checking if there is error text.  If not, there are no results
00170                          * from the SQL - it could have been a statement such as DELETE or
00171                          * INSERT.
00172              */
00173 
00174             errmsg = DbErrmsg(handle);
00175             if (errmsg && *errmsg) {
00176 
00177                                 /* Error text, so error occurred.  Output message & tidy up */
00178 
00179                 status = MsgLog(DBS_SQLFAIL, errmsg);
00180             }
00181                         /*
00182                          * else {
00183                          *
00184                          *              No error, so we just don't have any results.
00185                          * }
00186                          */
00187 
00188                         /*
00189                          * Regardless of what heppened, there is no result set, so free up
00190                          * allocated memory.
00191                          */
00192 
00193                         MemFree(*result);
00194                         *result = NULL;
00195         }
00196         else {
00197 
00198                         /*
00199                          * Success. "result" holds the result set.  Store the number of
00200                          * fields along with the length of each one for possible later use.
00201                          */
00202 
00203                         (*result)->count = sqlite3_data_count((sqlite3_stmt*) (*result)->data);
00204                 }
00205     }
00206         else if (status == SQLITE_DONE)
00207         {
00208                 /* Correct for one-shot statements like insert etc 
00209          * finalise the statement to avoid locking the database */
00210                 status = sqlite3_finalize((sqlite3_stmt*) (*result)->data);
00211 
00212                 MemFree(*result);
00213                 *result = NULL;
00214         }
00215     else {
00216 
00217         /* Query failed.  Log the error and free up the structure */
00218 
00219         status = MsgLog(DBS_SQLFAIL, DbErrmsg(handle));
00220                 MemFree(*result);
00221                 *result = NULL;
00222     }
00223 
00224     return status;
00225 }
00226 
00227 /*+
00228  * DbFreeResult - Free Result
00229  *
00230  * Description:
00231  *      Frees up resources allocated for the result by DbExecuteSql.
00232  *
00233  * Arguments:
00234  *      DB_RESULT result
00235  *          Handle to the query result. May be NULL, in which case this
00236  *          function is a no-op.
00237  *
00238  *          If invalid, an error message will be output.
00239 -*/
00240 
00241 void DbFreeResult(DB_RESULT result)
00242 {
00243     if (result) {
00244                 if (result->magic == DB_RESULT_MAGIC) {
00245 
00246                         /* Free up data */
00247 
00248                         sqlite3_finalize(result->data);
00249                         MemFree(result);
00250                         result = NULL;
00251                 }
00252                 else {
00253 
00254                         /* Invalid structure - output a warning but do nothing */
00255 
00256                         (void) MsgLog(DBS_INVARG, "DbFreeResult");
00257                 }
00258     }
00259 
00260     return;
00261 }
00262 
00263 
00264 
00265 /*+
00266  * DbFetchRow - Fetch Row from Result
00267  *
00268  * Description:
00269  *              Steps to the next row in the result set.
00270  *
00271  * Arguments:
00272  *              DB_RESULT result
00273  *                      The result handle returned by the call to DbExecuteSql.
00274  *
00275  *              DB_ROW* row
00276  *                      This is really just the same as RESULT for sqlite, but it is left
00277  *                      in for MySQL compatibility.
00278  *
00279  * Returns:
00280  *              int
00281  *                      0       Success, row information returned
00282  *                      -1  Success, no more rows for this result
00283  *                      Other       Error code or error number from DbErrno().
00284 -*/
00285 
00286 int DbFetchRow(DB_RESULT result, DB_ROW* row)
00287 {
00288         int                     status = 0;                     /* Status return */
00289 
00290         if (result && (result->magic == DB_RESULT_MAGIC) && row) {
00291 
00292                 /* There is a result structure (and row pointer), do something */
00293 
00294                 if (result->first_row == 1)
00295                 {
00296                         result->first_row = 0;
00297                         *row = (DB_ROW) MemCalloc(1, sizeof(struct db_row));
00298                         (*row)->magic = DB_ROW_MAGIC;
00299                         (*row)->result=result;
00300                 }
00301                 else
00302                 {
00303                         status = sqlite3_step(result->data);
00304                         if (status == SQLITE_DONE) {
00305                                 /* End of result set */
00306                 /* leave freeing the row to the calling function */
00307                                 /* *row = NULL; */
00308 
00309                                 status = -1;
00310                         }
00311                         else if (status == SQLITE_ROW)
00312                         {
00313                                 *row = (DB_ROW) MemCalloc(1, sizeof(struct db_row));
00314                                 (*row)->magic = DB_ROW_MAGIC;
00315                                 (*row)->result=result;
00316                                 status = 0;
00317                         }
00318                 }
00319         }
00320         else if (row) {
00321                 *row = NULL; /* no results to report */
00322                 status = -1;
00323         }
00324         else{
00325                 status = MsgLog(DBS_INVARG, "DbFetchRow");
00326 
00327         }
00328 
00329         return status;
00330 }
00331 
00332 
00333 
00334 /*+
00335  * DbFreeRow - Free Row
00336  *
00337  * Description:
00338  *      Frees up resources allocated for the row.
00339  *
00340  * Arguments:
00341  *      DB_RESULT result
00342  *          Handle to the query result. May be NULL, in which case this
00343  *          function is a no-op.
00344 -*/
00345 
00346 void DbFreeRow(DB_ROW row)
00347 {
00348     if (row) {
00349                 if (row->magic == DB_ROW_MAGIC) {
00350                         MemFree(row);
00351                 }
00352                 else {
00353 
00354                         /* Output warning, but otherwise do nothing */
00355 
00356                         (void) MsgLog(DBS_INVARG, "DbFreeRow");
00357                 }
00358     }
00359 
00360     return;
00361 }
00362 
00363 
00364 
00365 /*+
00366  * DbString - Return String Value
00367  *
00368  * Description:
00369  *      Returns string value from the current row.
00370  *
00371  * Arguments:
00372  *      DB_ROW row
00373  *          Pointer to the row object.
00374  *
00375  *      int field_index
00376  *          Index of the value required.
00377  *
00378  *      char** result
00379  *          Value of the field.  It is up to the caller to free it with
00380  *          a call to DbStringFree().  Note that this can be NULL if the
00381  *          corresponding field is NULL.
00382  *
00383  * Returns:
00384  *      int
00385  *              0               Success
00386  *              Other   Some error.  A message will have been output
00387 -*/
00388 
00389 int DbString(DB_ROW row, int field_index, char** result)
00390 {
00391         int                             status = 0;                     /* Status return */
00392         unsigned long   width;                      /* Width of column */
00393 
00394         /* Check arguments */
00395 
00396         if (row && (row->magic == DB_ROW_MAGIC) && result) {
00397 
00398                 /* Is the index requested valid? */
00399 
00400                 if ((field_index >= 0) && (field_index < row->result->count)) {
00401 
00402                         /* Get the width of the column */
00403 
00404                         width = sqlite3_column_bytes(row->result->data, field_index);
00405 
00406                         /* Get string into null-terminated form */
00407 
00408                         if (sqlite3_column_text(row->result->data, field_index) != NULL) {
00409                 /* TODO replece the below with strdup or StrStrdup ? */
00410                                 *result = MemMalloc(width + 1);
00411                                 memcpy(*result, sqlite3_column_text(row->result->data, field_index), width);
00412                                 (*result)[width] = 0;
00413                         }
00414                         else {
00415                                 *result = NULL;
00416                         }
00417                 }
00418                 else {
00419 
00420                         /* Invalid field, tell the user */
00421 
00422                         status = MsgLog(DBS_INVINDEX, field_index, row->result->count);
00423                 }
00424 
00425         }
00426         else {
00427 
00428                 /* Problem with the command arguments */
00429 
00430                 status = MsgLog(DBS_INVARG, "DbString");
00431         }
00432 
00433     return status;
00434 
00435 }
00436 
00437 
00438 /*+
00439  * DbStringFree - Free String Returned by DbString
00440  *
00441  * Description:
00442  *      Frees the pointer-to string.
00443  *
00444  * Arguments:
00445  *      char* string
00446  *          String allocated by DbString.  On exit, this pointer is invalid.
00447 -*/
00448 
00449 void DbStringFree(char* string)
00450 {
00451     MemFree(string);
00452 }
00453 
00454 /*+
00455  * DbBeginTransaction - Start a (non-nested) transaction
00456  *
00457  * Description:
00458  *      
00459  *
00460  * Arguments:
00461  *              NONE
00462 -*/
00463 
00464 int DbBeginTransaction(void)
00465 {
00466     const char* sql = "begin transaction";
00467     return DbExecuteSqlNoResult(DbHandle(), sql);
00468 }
00469 
00470 /*+
00471  * DbCommit - End a (non-nested) transaction by commiting it
00472  *
00473  * Description:
00474  *      
00475  *
00476  * Arguments:
00477  *              NONE
00478 -*/
00479 
00480 int DbCommit(void)
00481 {
00482     const char* sql = "commit transaction";
00483     return DbExecuteSqlNoResult(DbHandle(), sql);
00484 }
00485 
00486 /*+
00487  * DbRollback - End a (non-nested) transaction by rolling it back
00488  *
00489  * Description:
00490  *      
00491  *
00492  * Arguments:
00493  *              NONE
00494 -*/
00495 
00496 int DbRollback(void)
00497 {
00498     const char* sql = "rollback transaction";
00499     return DbExecuteSqlNoResult(DbHandle(), sql);
00500 }