OpenDNSSEC-enforcer 1.3.0
/build/buildd/opendnssec-1.3.0/enforcer/ksm/database_support_mysql.c
Go to the documentation of this file.
00001 /*
00002  * $Id: database_support_mysql.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 <mysql.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         return MsgLog(DBS_INVARG, "NULL id");
00127     }
00128 
00129         status = DbUnsignedLong(row, 0, &rowid);
00130         *id = (DB_ID) rowid;            /* Do the conversion between types here */
00131 
00132         return status;
00133 }
00134         
00135 
00136 
00137 
00138 /*+
00139  * DbInt - Return Integer from Field
00140  *
00141  * Description:
00142  *              Returns an integer value from the current row.
00143  *
00144  * Arguments:
00145  *      DB_ROW row
00146  *          Pointer to the row object.
00147  *
00148  *      int field_index
00149  *          Index of the value required.
00150  *
00151  *      int *value
00152  *              Value returned.
00153  *
00154  * Returns:
00155  *      int
00156  *              Status return:
00157  *                      0               Success
00158  *                      Other   Error accessing data.  A message will have been output.
00159 -*/
00160 
00161 int DbInt(DB_ROW row, int field_index, int *value)
00162 {
00163     char*   buffer = NULL;      /* Text buffer for returned string */
00164         int             status;             /* Status return */
00165 
00166         /* Access the text in the field */
00167 
00168     status = DbString(row, field_index, &buffer);
00169         if (status == 0) {
00170 
00171                 /* Got the string, can we convert it? */
00172 
00173                 if (buffer != NULL) {
00174 
00175                         /* Not best-efforts - ignore trailing non-numeric values */
00176 
00177                         status = StrStrtoi(buffer, value);
00178                         if (status == -1) {
00179 
00180                                 /* Could not translate the string to an integer */
00181 
00182                                 status = MsgLog(DBS_NOTINT, buffer);
00183                                 *value = 0;
00184                         }
00185                         DbStringFree(buffer);
00186                 }
00187                 else {
00188 
00189                         /* Field is NULL, return 0 */
00190 
00191                         *value = 0;
00192                 }
00193         }
00194 
00195     return status;
00196 }
00197 
00198 
00199 
00200 /*+
00201  * DbUnsignedLong - Return Unsigned Long from Field
00202  *
00203  * Description:
00204  *              Returns an integer value from the current row.
00205  *
00206  * Arguments:
00207  *      DB_ROW row
00208  *          Pointer to the row object.
00209  *
00210  *      int field_index
00211  *          Index of the value required.
00212  *
00213  *      unsigned long *value
00214  *              Value returned.
00215  *
00216  * Returns:
00217  *      int
00218  *              Status return:
00219  *                      0               Success
00220  *                      Other   Error accessing data.  A message will have been output.
00221 -*/
00222 
00223 int DbUnsignedLong(DB_ROW row, int field_index, unsigned long *value)
00224 {
00225     char*   buffer = NULL;              /* Text buffer for returned string */
00226         int             status;         /* Status return */
00227 
00228         /* Access the text in the field */
00229 
00230     status = DbString(row, field_index, &buffer);
00231         if (status == 0) {
00232 
00233                 /* Got the string, can we convert it? */
00234 
00235                 if (buffer != NULL) {
00236 
00237                         /* Not best-efforts - ignore trailing non-numeric values */
00238 
00239                         status = StrStrtoul(buffer, value);
00240                         if (status == -1) {
00241 
00242                                 /* Could not translate the string to an unsigned long */
00243 
00244                                 status = MsgLog(DBS_NOTINT, buffer);
00245                                 *value = 0;
00246                         }
00247                         DbStringFree(buffer);
00248                 }
00249                 else {
00250 
00251                         /* Field is NULL, return 0 */
00252 
00253                         *value = 0;
00254                 }
00255         }
00256 
00257     return status;
00258 }
00259 
00260 
00261 
00262 /*+
00263  * DbIntQuery - Perform Query Returning Single Integer
00264  *
00265  * Description:
00266  *      Many queries are of the form:
00267  *
00268  *          SELECT COUNT(*) FROM ...
00269  *      or
00270  *          SELECT <single integer value> FROM ...
00271  *
00272  *      This function performs the query and returns the single value.
00273  *
00274  * Arguments:
00275  *      DB_HANDLE handle
00276  *          Handle to the currently opened database.
00277  *
00278  *      int* value
00279  *          Result of the query.  Note that if the query returns no rows,
00280  *          a zero is returned.
00281  *
00282  *      const char* query
00283  *          Query to run.
00284  *
00285  * Returns:
00286  *      int
00287  *          0           Success
00288  *          Other       Error (a message will have been output)
00289 -*/
00290 
00291 int DbIntQuery(DB_HANDLE handle, int* value, const char* query)
00292 {
00293         DB_RESULT       result = NULL;  /* Result object */
00294         DB_ROW          row = NULL;     /* Row object */
00295     int                 status;         /* Status return */
00296 
00297     status = DbExecuteSql(handle, query, &result);
00298     if (status == 0) {
00299        
00300         /* Get first row */
00301         status = DbFetchRow(result, &row);
00302                 if (status == 0) {
00303             /* Got the row, so convert to integer */
00304 
00305             status = DbInt(row, 0, value);
00306 
00307                         /* Query succeeded, but are there any more rows? */
00308                 if (DbFetchRow(result, &row) != -1) {
00309                 (void) MsgLog(DBS_TOOMANYROW, query);   /* Too much data */
00310                 }
00311         }
00312         else 
00313         {
00314                         status = MsgLog(DBS_NORESULT);  /* Query did not return a result */
00315         }
00316 
00317                 DbFreeResult(result);
00318                 DbFreeRow(row);
00319     }
00320 
00321     return status;
00322 }
00323 
00324 
00325 /*+
00326  * DbStringBuffer - Return String Value into User-Supplied Buffer
00327  *
00328  * Description:
00329  *      Returns string value from the current row into a user-supplied
00330  *      buffer.  The returned value is truncated if required.
00331  *
00332  * Arguments:
00333  *      DB_ROW row
00334  *          Pointer to the row object.
00335  *
00336  *      int field_index
00337  *          Index of the value required.
00338  *
00339  *      char* buffer
00340  *          Null-terminated buffer into which the data is put.  If the returned
00341  *          string is NULL, the buffer will contain a zero-length string.  There
00342  *          is no way to distinguish between this and the database holding an
00343  *          empty string.
00344  *
00345  *      size_t buflen
00346  *          Length of the buffer.
00347  *
00348  * Returns:
00349  *              int
00350  *                      0               Success
00351  *                      Other   Error.  A message will have been output.
00352 -*/
00353 
00354 int DbStringBuffer(DB_ROW row, int field_index, char* buffer, size_t buflen)
00355 {
00356         char*   data;           /* Data returned from DbString */
00357         int             status;         /* Status return */
00358 
00359         if (row && (row->magic == DB_ROW_MAGIC) && buffer && (buflen != 0)) {
00360 
00361                 /* Arguments OK, get the information */
00362 
00363                 status = DbString(row, field_index, &data);
00364                 if (status == 0) {
00365 
00366                         /* Success, copy the data into destination & free buffer
00367                Note the StrStrncpy copes with data == NULL */
00368 
00369                         StrStrncpy(buffer, data, buflen);
00370                         DbStringFree(data);
00371                 }
00372         }
00373         else {
00374 
00375                 /* Invalid srguments, notify the user */
00376 
00377                 status = MsgLog(DBS_INVARG, "DbStringBuffer");
00378         }
00379 
00380         return status;
00381 }
00382 
00383 
00384 
00385 /*+
00386  * DbErrno - Return Last Error Number
00387  *
00388  * Description:
00389  *              Returns the numeric code associated with the last operation
00390  *              on this connection that gave an error.
00391  *
00392  * Arguments:
00393  *      DB_HANDLE handle
00394  *          Handle to an open database.
00395  *
00396  * Returns:
00397  *              int
00398  *                      Error number.
00399 -*/
00400 
00401 int DbErrno(DB_HANDLE handle)
00402 {
00403     return mysql_errno((MYSQL*) handle);
00404 }
00405 
00406 
00407 
00408 /*+
00409  * DbErrmsg - Return Last Error Message
00410  *
00411  * Description:
00412  *      Returns the last error on this connection.  This is just an
00413  *      encapsulation of mysql_error.
00414  *
00415  * Arguments:
00416  *      DB_HANDLE handle
00417  *          Handle to an open database.
00418  *
00419  * Returns:
00420  *      const char*
00421  *          Error string.  This should be copied and must not be freed.
00422 -*/
00423 
00424 const char* DbErrmsg(DB_HANDLE handle)
00425 {
00426     return mysql_error((MYSQL*) handle);
00427 }
00428 
00429 
00430 /*+
00431  * DbLastRowId - Return Last Row ID
00432  *
00433  * Description:
00434  *              Returns the ID field of the last row inserted.
00435  *
00436  *              All tables are assumed to include an auto-incrementing ID field.  Apart
00437  *              from providing the unique primary key, this is a relatively
00438  *              implementation-unique way of uniquely identifying a row in a table.
00439  *
00440  * Arguments:
00441  *              DB_HANDLE handle
00442  *                      Handle to the database connection.
00443  *
00444  *              DB_ID* id
00445  *                      ID of the last row inserted (into any table) on this connection.
00446  *
00447  * Returns:
00448  *              int
00449  *                      Status return
00450  *
00451  *                              0               Success
00452  *                              Other   Error code.  An error message will have been output.
00453 -*/
00454 
00455 int DbLastRowId(DB_HANDLE handle, DB_ID* id)
00456 {
00457 
00458     if (id == NULL) {
00459         return MsgLog(DBS_INVARG, "NULL id");
00460     }
00461 
00462         *id = (DB_ID) mysql_insert_id((MYSQL*) handle);
00463 
00464         /*
00465          * In MySql, there is no error code; a value of 0 is returned if there
00466          * is no matching row.  In this case, convert it to an error code.
00467          */
00468 
00469         return (*id != 0) ? 0 : DBS_NOSUCHROW;
00470 }