Fix issue #7 : SQLITECPP_ENABLE_ASSERT_HANDLER

- SQLITECPP_ASSERT() can call a user defined SQLite::assertion_failed() handler.
This commit is contained in:
Sébastien Rombauts 2013-11-01 21:10:44 +01:00
parent 8bf7339e6b
commit ecd22dc112
10 changed files with 452 additions and 375 deletions

View File

@ -16,6 +16,9 @@ if (SQLITE_ENABLE_COLUMN_METADATA)
add_definitions(-DSQLITE_ENABLE_COLUMN_METADATA) add_definitions(-DSQLITE_ENABLE_COLUMN_METADATA)
endif() endif()
add_definitions(-DSQLITECPP_ENABLE_ASSERT_HANDLER)
if (MSVC) if (MSVC)
# build the SQLite3 C library for Windows (for ease of use) # build the SQLite3 C library for Windows (for ease of use)
add_subdirectory (sqlite3) add_subdirectory (sqlite3)

View File

@ -205,6 +205,25 @@ catch (std::exception& e)
} }
``` ```
### How to handle in assertion in SQLiteC++:
Exceptions shall not be used in destructors, so SQLiteC++ use SQLITECPP_ASSERT() to check for errors in destructors.
If you don't want assert() to be called, you have to enable and define an assert handler as shown below.
```C++
#ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
namespace SQLite
{
/// definition of the assertion handler enabled when SQLITECPP_ENABLE_ASSERT_HANDLER is defined in the project (CMakeList.txt)
void assertion_failed(const char* apFile, const long apLine, const char* apFunc, const char* apExpr, const char* apMsg)
{
// Print a message to the standard error output stream, and abort the program.
std::cerr << apFile << ":" << apLine << ":" << " error: assertion (" << apExpr << ") failed in '" << apFunc << "' (" << apMsg << ")\n";
std::abort();
}
}
#endif
```
## How to contribute ## How to contribute
### GitHub website ### GitHub website
The most efficient way to help and contribute to this wrapper project is to The most efficient way to help and contribute to this wrapper project is to

View File

@ -14,10 +14,25 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "../../src/SQLiteC++.h" #include "../../src/SQLiteC++.h"
#ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
namespace SQLite
{
/// definition of the assertion handler enabled when SQLITECPP_ENABLE_ASSERT_HANDLER is defined in the project (CMakeList.txt)
void assertion_failed(const char* apFile, const long apLine, const char* apFunc, const char* apExpr, const char* apMsg)
{
// Print a message to the standard error output stream, and abort the program.
std::cerr << apFile << ":" << apLine << ":" << " error: assertion (" << apExpr << ") failed in " << apFunc << ": '" << apMsg << "'\n";
std::abort();
}
}
#endif
/// Example Database
static const char* filename_example_db3 = "examples/example1/example.db3"; static const char* filename_example_db3 = "examples/example1/example.db3";
/// Image
static const char* filename_logo_png = "examples/example1/logo.png"; static const char* filename_logo_png = "examples/example1/logo.png";
@ -107,7 +122,6 @@ int main (void)
} }
#endif #endif
std::cout << "row (" << id << ", \"" << value2.c_str() << "\" " << bytes << " bytes, " << weight << ")\n"; std::cout << "row (" << id << ", \"" << value2.c_str() << "\" " << bytes << " bytes, " << weight << ")\n";
} }
// Reset the query to use it again // Reset the query to use it again
@ -327,7 +341,7 @@ int main (void)
size = colBlob.getBytes (); size = colBlob.getBytes ();
std::cout << "row (" << query.getColumn(0) << ", size=" << size << ")\n"; std::cout << "row (" << query.getColumn(0) << ", size=" << size << ")\n";
size_t sizew = fwrite(blob, 1, size, fp); size_t sizew = fwrite(blob, 1, size, fp);
SQLITE_CPP_ASSERT(sizew == size); SQLITECPP_ASSERT(sizew == size, "fwrite failed"); // See SQLITECPP_ENABLE_ASSERT_HANDLER
fclose (fp); fclose (fp);
} }
} }

56
src/Assert.h Normal file
View File

@ -0,0 +1,56 @@
/**
* @file Assert.h
* @ingroup SQLiteCpp
* @brief Definition of the SQLITECPP_ASSERT() macro.
*
* Copyright (c) 2012-2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
*
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
* or copy at http://opensource.org/licenses/MIT)
*/
#pragma once
#include <cassert>
/**
* @def SQLITECPP_ASSERT SQLITECPP_ASSERT() is used in destructors, where exceptions shall not be thrown
*
* Define SQLITECPP_ENABLE_ASSERT_HANDLER at the project level
* and define a SQLite::assertion_failed() assertion handler
* to tell SQLiteC++ to use it instead of assert() when an assertion fail.
*/
#ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
// if an assert handler is provided by user code, use it instead of assert()
namespace SQLite
{
// declaration of the assert handler to define in user code
void assertion_failed(const char* apFile, const long apLine, const char* apFunc, const char* apExpr, const char* apMsg);
#ifdef _MSC_VER
#define __func__ __FUNCTION__
#endif
// call the assert handler provided by user code
#define SQLITECPP_ASSERT(expression,message) \
if (!(expression)) SQLite::assertion_failed(__FILE__, __LINE__, __func__, #expression, message)
}
#else
// if no assert handler provided by user code, use standard assert()
#ifndef NDEBUG
// in debug mode, assert() :
#define SQLITECPP_ASSERT(expression,message) assert(expression)
#else
// in release mode, nothing :
#define SQLITECPP_ASSERT(expression,message) (expression)
#endif
#endif
#ifdef _WIN32
#pragma warning(disable:4290) // Disable warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
#endif

View File

@ -12,6 +12,7 @@
# add sources of the wrapper as a "SQLiteCpp" static library # add sources of the wrapper as a "SQLiteCpp" static library
add_library (SQLiteCpp add_library (SQLiteCpp
SQLiteC++.h SQLiteC++.h
Assert.h
Column.cpp Column.cpp
Column.h Column.h
Database.cpp Database.cpp

View File

@ -11,6 +11,7 @@
#include "Database.h" #include "Database.h"
#include "Statement.h" #include "Statement.h"
#include "Assert.h"
#include "Exception.h" #include "Exception.h"
@ -37,8 +38,7 @@ Database::~Database(void) throw() // nothrow
{ {
int ret = sqlite3_close(mpSQLite); int ret = sqlite3_close(mpSQLite);
// Never throw an exception in a destructor // Never throw an exception in a destructor
//std::cout << sqlite3_errmsg(mpSQLite) << std::endl; SQLITECPP_ASSERT (SQLITE_OK == ret, sqlite3_errmsg(mpSQLite)); // See SQLITECPP_ENABLE_ASSERT_HANDLER
SQLITE_CPP_ASSERT (SQLITE_OK == ret);
} }
// Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT...). // Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT...).

View File

@ -11,23 +11,6 @@
#pragma once #pragma once
#include <stdexcept> #include <stdexcept>
#include <cassert>
// assert() is used in destructors, where exceptions are not allowed
// here you can chose if you want to use them or not
#ifndef NDEBUG
// in debug mode :
#define SQLITE_CPP_ASSERT(expression) assert(expression)
#else
// in release mode :
#define SQLITE_CPP_ASSERT(expression) (expression)
#endif
#ifdef _WIN32
#pragma warning(disable:4290) // Disable warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
#endif
namespace SQLite namespace SQLite

View File

@ -18,6 +18,7 @@
// Include useful headers of SQLiteC++ // Include useful headers of SQLiteC++
#include "Assert.h"
#include "Exception.h" #include "Exception.h"
#include "Database.h" #include "Database.h"
#include "Statement.h" #include "Statement.h"

View File

@ -12,6 +12,7 @@
#include "Database.h" #include "Database.h"
#include "Column.h" #include "Column.h"
#include "Assert.h"
#include "Exception.h" #include "Exception.h"
@ -316,8 +317,7 @@ Statement::Ptr::~Ptr(void) throw() // nothrow
// as no Statement not Column objet use it anymore // as no Statement not Column objet use it anymore
int ret = sqlite3_finalize(mpStmt); int ret = sqlite3_finalize(mpStmt);
// Never throw an exception in a destructor // Never throw an exception in a destructor
//std::cout << sqlite3_errmsg(mpSQLite) << std::endl; SQLITECPP_ASSERT (SQLITE_OK == ret, sqlite3_errmsg(mpSQLite)); // See SQLITECPP_ENABLE_ASSERT_HANDLER
SQLITE_CPP_ASSERT (SQLITE_OK == ret);
// and delete the reference counter // and delete the reference counter
delete mpRefCount; delete mpRefCount;

View File

@ -11,6 +11,7 @@
#include "Transaction.h" #include "Transaction.h"
#include "Database.h" #include "Database.h"
#include "Assert.h"
#include "Exception.h" #include "Exception.h"
@ -35,11 +36,10 @@ Transaction::~Transaction(void) throw() // nothrow
{ {
mDatabase.exec("ROLLBACK"); mDatabase.exec("ROLLBACK");
} }
catch (SQLite::Exception& /*e*/) catch (SQLite::Exception& e)
{ {
// Never throw an exception in a destructor // Never throw an exception in a destructor
//std::cout << e.what() << std::endl; SQLITECPP_ASSERT(false, e.what()); // See SQLITECPP_ENABLE_ASSERT_HANDLER
SQLITE_CPP_ASSERT(false);
} }
} }
} }