diff options
-rw-r--r-- | database/sqlite/sqlite.c | 118 | ||||
-rw-r--r-- | database/sqlite/sqlite.h | 33 |
2 files changed, 133 insertions, 18 deletions
diff --git a/database/sqlite/sqlite.c b/database/sqlite/sqlite.c index 0303b29..2133df8 100644 --- a/database/sqlite/sqlite.c +++ b/database/sqlite/sqlite.c @@ -54,6 +54,23 @@ * @} */ +/** + * Internal function for setting the error fields. + */ +static void _sqlite_set_error(dbresult *dbres, ErrorSeverity sev, const char *query, const char *fmt, ...) +{ + char errbuf[4098]; + va_list ap; + + va_start(ap, fmt); + memset(&errbuf, 0, 4098); + vsnprintf(errbuf, 4096, fmt, ap); + va_end(ap); + + dbres->errSeverity = sev; + dbres->errMsg = strdup(errbuf); + dbres->query = strdup(query); +} /** * Internal function. Free up a dbresult structure. This function is available via the @@ -102,6 +119,11 @@ void _sqlite_free_results(dbresult *inres) free_nullsafe(NULL, hdr->name); free_nullsafe(NULL, hdr); } + + // Remove error messages and copy of the SQL query + inres->status = dbEMPTY; + free_nullsafe(NULL, inres->errMsg); + free_nullsafe(NULL, inres->query); free_nullsafe(NULL, inres); } @@ -220,6 +242,67 @@ static int _cb_parse_result(void *resultptr, int argc, char **argv, char **colNa return 0; } +/** + * Logs sqlite error messages via the eurephia log interface and returns an XML node with details + * (This function is only included if libxml2 is available) + * + * @param eurephiaCTX* eurephia context pointer, where logging will be performed + * @param dbresult* Pointer to the database result with the error message + * + */ +void sqlite_log_error(eurephiaCTX *ctx, dbresult *dbres) { + if( dbres == NULL ) { + eurephia_log(ctx, LOG_CRITICAL, 2, "Unknown error (NULL result)"); + return; + } + + if( dbres->status != dbSUCCESS ) { + eurephia_log(ctx, LOG_ERROR, 4, "SQL Error: %s", dbres->errMsg); + } + DEBUG(ctx, 33, "SQL Query: %s", dbres->query); +} + + +/** + * Logs sqlite error messages via the eurephia log interface and returns an XML node with details + * (This function is only included if libxml2 is available) + * + * @param eurephiaCTX* eurephia context pointer, where logging will be performed + * @param dbresult* Pointer to the database result with the error message + * + * @return An xmlNode pointer with more details of the error. + */ +#ifdef HAVE_LIBXML2 +xmlNode *sqlite_log_error_xml(eurephiaCTX *ctx, dbresult *dbres ) { + xmlNode *ret = NULL; + + sqlite_log_error(ctx, dbres); + if( dbres == NULL ) { + return NULL; + } + + ret = xmlNewNode(NULL, (xmlChar *) "SQLError"); + if( ret != NULL ) { + xmlNode *err_n = NULL; + xmlChar *errstr = NULL; + const xmlChar *ErrorSeverity_str[] = { + (xmlChar *) "Warning", + (xmlChar *) "Error", + (xmlChar *) "Critical", + (xmlChar *) "PANIC", + NULL + }; + + xmlNewProp(ret, (xmlChar *) "driver", (xmlChar *) "edb-sqlite.so"); + errstr = xmlCharStrdup(dbres->errMsg); + err_n = xmlNewTextChild(ret, NULL, (xmlChar *) "ErrorMessage", errstr); + xmlNewProp(err_n, (xmlChar *) "severity", ErrorSeverity_str[dbres->errSeverity]); + free_nullsafe(NULL, errstr); + } + return ret; +} +#endif + /** * Main function for query a SQLite3 database. @@ -236,35 +319,32 @@ dbresult *sqlite_query(eurephiaCTX *ctx, const char *fmt, ... ) { eDBconn *dbc = ctx->dbc; dbresult *dbres = NULL; - if( ctx->dbc == NULL ) { - eurephia_log(ctx, LOG_PANIC, 0, "No open database connection to perfom SQL query to"); - return NULL; - } - - if( ctx->context_type == ECTX_NO_PRIVILEGES ) { - eurephia_log(ctx, LOG_ERROR, 0, "Database query attempted from wrong context"); - return NULL; - } - - // prepare a new (global) result set ... - // do not delete the old ones, since we return this "global" - // result as a new individual result + // prepare a new result set ... dbres = malloc_nullsafe(ctx, sizeof(dbresult)+2); + dbres->status = dbEMPTY; dbres->num_tuples = 0; - + // prepare SQL query va_start(ap, fmt); sql = sqlite3_vmprintf(fmt, ap); va_end(ap); + if( ctx->dbc == NULL ) { + _sqlite_set_error(dbres, sevPANIC, sql, "No open database connection to perfom SQL query to"); + goto exit; + } + + if( ctx->context_type == ECTX_NO_PRIVILEGES ) { + _sqlite_set_error(dbres, sevCRITICAL, sql, "Database query attempted from wrong context"); + goto exit; + } + DEBUG(ctx, 25, "Doing SQL Query: %s", sql); rc = sqlite3_exec( (sqlite3 *) dbc->dbhandle, sql, _cb_parse_result, dbres, &errMsg ); if( rc != SQLITE_OK ) { - eurephia_log(ctx, LOG_ERROR, 0, "SQL Error: %s", errMsg); - sqlite3_free(sql); sql = NULL; + _sqlite_set_error(dbres, (dbres->num_tuples > 0 ? sevWARNING : sevERROR), sql, "%s", errMsg); sqlite3_free(errMsg); errMsg = NULL; - free_nullsafe(ctx, dbres); - return NULL; + goto exit; } if( strcasestr(sql, "INSERT INTO") != 0) { @@ -275,8 +355,10 @@ dbresult *sqlite_query(eurephiaCTX *ctx, const char *fmt, ... ) { dbres->affected_rows = sqlite3_changes((sqlite3 *) dbc->dbhandle); } + dbres->status = dbSUCCESS; dbres->srch_tuples = dbres->tuples; dbres->srch_headerrec = dbres->headerrec; + exit: sqlite3_free(sql); sql = NULL; return dbres; diff --git a/database/sqlite/sqlite.h b/database/sqlite/sqlite.h index ba4cac5..5a7c5fd 100644 --- a/database/sqlite/sqlite.h +++ b/database/sqlite/sqlite.h @@ -81,6 +81,24 @@ typedef struct __sqlite_tuples { /** + * Defines dbresult status types + */ +typedef enum _QueryStatus { dbEMPTY, /**< No SQL query has been performed */ + dbSUCCESS, /**< SQL query was successful */ + dbERROR, /**< SQL query failed */ + dbINVALID /**< Invalid dbresult (NULL value) */ +} QueryStatus; + +/** + * Defines error severities + */ +typedef enum _ErrorSeverity { sevWARNING, /**< Query returns some data, but with errors in completeing it */ + sevERROR, /**< Query could not complete, but may try again */ + sevCRITICAL, /**< Query failed and there is no point of trying again */ + sevPANIC /**< Query failed and eurephia should shutdown */ +} ErrorSeverity; + +/** * The main definition of the dbresult strucutre. This structure keeps the * complete information about both fields and values of all records from a query. * @@ -91,6 +109,9 @@ typedef struct __sqlite_tuples { * as possible. */ typedef struct __sqlite_dbresult { + QueryStatus status; /**< Indicates if the query was successful or not */ + char *query; /**< Copy of the parsed SQL query */ + // Query results _sqlite_tuples *tuples; /**< Pointer to the chains which contains field values */ _sqlite_header *headerrec; /**< Pointer to the chains with info about the field/columns */ @@ -102,6 +123,10 @@ typedef struct __sqlite_dbresult { // "Search" pointers _sqlite_tuples *srch_tuples; /**< "Cache" of the last record being looked up */ _sqlite_header *srch_headerrec; /**< "Cache" of the last header record being looked up */ + + // Error handling + ErrorSeverity errSeverity; /**< Severity of the error */ + char *errMsg; /**< If status == dbERROR, a error message can be found here */ } dbresult; @@ -110,6 +135,7 @@ typedef struct __sqlite_dbresult { */ typedef enum _SQLqueryType { SQL_SELECT, SQL_INSERT, SQL_UPDATE, SQL_DELETE } SQLqueryType; + /** * Free up a dbresult structure. This is the public interface for the * internal function _sqlite_free_results() @@ -118,9 +144,16 @@ typedef enum _SQLqueryType { SQL_SELECT, SQL_INSERT, SQL_UPDATE, SQL_DELETE } SQ */ #define sqlite_free_results(r) { _sqlite_free_results(r); r = NULL; } void _sqlite_free_results(dbresult *); + +void sqlite_log_error(eurephiaCTX *ctx, dbresult *dbres ); +#ifdef HAVE_LIBXML2 +xmlNode *sqlite_log_error_xml(eurephiaCTX *ctx, dbresult *dbres ); +#endif + dbresult *sqlite_query(eurephiaCTX *ctx, const char *, ...); dbresult *sqlite_query_mapped(eurephiaCTX *ctx, SQLqueryType type, const char *sqlstub, eDBfieldMap *valMap, eDBfieldMap *whereMap, const char *sortkeys); +#define sqlite_query_status(res) (QueryStatus) (res != NULL ? res->status : dbINVALID) char *sqlite_get_value(dbresult *res, int, int); #ifdef HAVE_LIBXML2 xmlNodePtr sqlite_xml_value(xmlNodePtr node, xmlFieldType xmltyp, char *name, dbresult *res, int row, int col); |