summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Sommerseth <dazo@users.sourceforge.net>2011-01-10 00:39:49 +0100
committerDavid Sommerseth <davids@redhat.com>2011-12-19 11:05:35 +0100
commitf0434a3ad51bf1159a78003a020eeb82a26dfc7f (patch)
tree905c7b9a18c80757822a2026746f4114d07df7e8
parent13834c822bc5763d2df1683ed81add55cf919729 (diff)
downloadeurephia-f0434a3ad51bf1159a78003a020eeb82a26dfc7f.tar.gz
eurephia-f0434a3ad51bf1159a78003a020eeb82a26dfc7f.tar.xz
eurephia-f0434a3ad51bf1159a78003a020eeb82a26dfc7f.zip
Implemented better error handling in the SQLite3 framework
The core sqlite_query() function will now always return a pointer to a dbresult structure. This structure now contains a query status and the error message from the sqlite3 backend if something went wrong. This means that error checking from now on should use the sqlite_query_status() macro and not to check if sqlite_query() returns NULL. Another fundamental change is that sqlite_free_results() must always be called on the dbresult structure now, to free the memory used by either data from the query or the error message. Signed-off-by: David Sommerseth <dazo@users.sourceforge.net>
-rw-r--r--database/sqlite/sqlite.c118
-rw-r--r--database/sqlite/sqlite.h33
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);