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

@ -14,7 +14,10 @@ option (SQLITE_ENABLE_COLUMN_METADATA
"Enable Column::getName(). Require support from sqlite3 library." OFF) "Enable Column::getName(). Require support from sqlite3 library." OFF)
if (SQLITE_ENABLE_COLUMN_METADATA) 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)

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

@ -1,350 +1,364 @@
/** /**
* @file main.cpp * @file main.cpp
* @brief A few short examples in a row. * @brief A few short examples in a row.
* *
* Demonstrate how-to use the SQLite++ wrapper * Demonstrate how-to use the SQLite++ wrapper
* *
* Copyright (c) 2012-2013 Sebastien Rombauts (sebastien.rombauts@gmail.com) * Copyright (c) 2012-2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
* *
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
* or copy at http://opensource.org/licenses/MIT) * or copy at http://opensource.org/licenses/MIT)
*/ */
#include <iostream> #include <iostream>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "../../src/SQLiteC++.h"
#include "../../src/SQLiteC++.h"
static const char* filename_example_db3 = "examples/example1/example.db3"; #ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
static const char* filename_logo_png = "examples/example1/logo.png"; namespace SQLite
{
/// definition of the assertion handler enabled when SQLITECPP_ENABLE_ASSERT_HANDLER is defined in the project (CMakeList.txt)
/// Object Oriented Basic example void assertion_failed(const char* apFile, const long apLine, const char* apFunc, const char* apExpr, const char* apMsg)
class Example {
{ // Print a message to the standard error output stream, and abort the program.
public: std::cerr << apFile << ":" << apLine << ":" << " error: assertion (" << apExpr << ") failed in " << apFunc << ": '" << apMsg << "'\n";
// Constructor std::abort();
Example(void) : }
mDb(filename_example_db3), // Open a database file in readonly mode }
mQuery(mDb, "SELECT * FROM test WHERE weight > :min_weight")// Compile a SQL query, containing one parameter (index 1) #endif
{
} /// Example Database
virtual ~Example(void) static const char* filename_example_db3 = "examples/example1/example.db3";
{ /// Image
} static const char* filename_logo_png = "examples/example1/logo.png";
/// List the rows where the "weight" column is greater than the provided aParamValue
void ListGreaterThan (const int aParamValue) /// Object Oriented Basic example
{ class Example
std::cout << "ListGreaterThan (" << aParamValue << ")\n"; {
public:
// Bind the integer value provided to the first parameter of the SQL query // Constructor
mQuery.bind(":min_weight", aParamValue); // same as mQuery.bind(1, aParamValue); Example(void) :
mDb(filename_example_db3), // Open a database file in readonly mode
// Loop to execute the query step by step, to get one a row of results at a time mQuery(mDb, "SELECT * FROM test WHERE weight > :min_weight")// Compile a SQL query, containing one parameter (index 1)
while (mQuery.executeStep()) {
{ }
std::cout << "row (" << mQuery.getColumn(0) << ", \"" << mQuery.getColumn(1) << "\", " << mQuery.getColumn(2) << ")\n"; virtual ~Example(void)
} {
}
// Reset the query to be able to use it again later
mQuery.reset(); /// List the rows where the "weight" column is greater than the provided aParamValue
} void ListGreaterThan (const int aParamValue)
{
private: std::cout << "ListGreaterThan (" << aParamValue << ")\n";
SQLite::Database mDb; ///< Database connection
SQLite::Statement mQuery; ///< Database prepared SQL query // Bind the integer value provided to the first parameter of the SQL query
}; mQuery.bind(":min_weight", aParamValue); // same as mQuery.bind(1, aParamValue);
// Loop to execute the query step by step, to get one a row of results at a time
int main (void) while (mQuery.executeStep())
{ {
// Basic example (1/6) : std::cout << "row (" << mQuery.getColumn(0) << ", \"" << mQuery.getColumn(1) << "\", " << mQuery.getColumn(2) << ")\n";
try }
{
// Open a database file in readonly mode // Reset the query to be able to use it again later
SQLite::Database db(filename_example_db3); // SQLITE_OPEN_READONLY mQuery.reset();
std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n"; }
// Test if the 'test' table exists private:
bool bExists = db.tableExists("test"); SQLite::Database mDb; ///< Database connection
std::cout << "SQLite table 'test' exists=" << bExists << "\n"; SQLite::Statement mQuery; ///< Database prepared SQL query
};
// Get a single value result with an easy to use shortcut
std::string value = db.execAndGet("SELECT value FROM test WHERE id=2");
std::cout << "execAndGet=" << value.c_str() << std::endl; int main (void)
{
// Compile a SQL query, containing one parameter (index 1) // Basic example (1/6) :
SQLite::Statement query(db, "SELECT * FROM test WHERE weight > ?"); try
std::cout << "SQLite statement '" << query.getQuery().c_str() << "' compiled (" << query.getColumnCount () << " columns in the result)\n"; {
// Bind the integer value 2 to the first parameter of the SQL query // Open a database file in readonly mode
query.bind(1, 2); SQLite::Database db(filename_example_db3); // SQLITE_OPEN_READONLY
std::cout << "binded with integer value '2' :\n"; std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";
// Loop to execute the query step by step, to get one a row of results at a time // Test if the 'test' table exists
while (query.executeStep()) bool bExists = db.tableExists("test");
{ std::cout << "SQLite table 'test' exists=" << bExists << "\n";
// Demonstrate how to get some typed column value (and the equivalent explicit call)
int id = query.getColumn(0); // = query.getColumn(0).getInt() // Get a single value result with an easy to use shortcut
//const char* pvalue = query.getColumn(1); // = query.getColumn(1).getText() std::string value = db.execAndGet("SELECT value FROM test WHERE id=2");
std::string value2 = query.getColumn(1); // = query.getColumn(1).getText() std::cout << "execAndGet=" << value.c_str() << std::endl;
int bytes = query.getColumn(1).getBytes();
double weight = query.getColumn(2); // = query.getColumn(2).getInt() // Compile a SQL query, containing one parameter (index 1)
SQLite::Statement query(db, "SELECT * FROM test WHERE weight > ?");
#ifdef SQLITE_ENABLE_COLUMN_METADATA std::cout << "SQLite statement '" << query.getQuery().c_str() << "' compiled (" << query.getColumnCount () << " columns in the result)\n";
static bool bFirst = true; // Bind the integer value 2 to the first parameter of the SQL query
if (bFirst) query.bind(1, 2);
{ std::cout << "binded with integer value '2' :\n";
// Show how to get the name of a column.
// Requires the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro to be also defined at compile times of the SQLite library. // Loop to execute the query step by step, to get one a row of results at a time
std::string name0 = query.getColumn(0).getName(); while (query.executeStep())
std::string name1 = query.getColumn(1).getName(); {
std::string name2 = query.getColumn(2).getName(); // Demonstrate how to get some typed column value (and the equivalent explicit call)
std::cout << "table 'test' [\"" << name0.c_str() << "\", \"" << name1.c_str() << "\", \"" << name2.c_str() << "\"]\n"; int id = query.getColumn(0); // = query.getColumn(0).getInt()
bFirst = false; //const char* pvalue = query.getColumn(1); // = query.getColumn(1).getText()
} std::string value2 = query.getColumn(1); // = query.getColumn(1).getText()
#endif int bytes = query.getColumn(1).getBytes();
std::cout << "row (" << id << ", \"" << value2.c_str() << "\" " << bytes << " bytes, " << weight << ")\n"; double weight = query.getColumn(2); // = query.getColumn(2).getInt()
} #ifdef SQLITE_ENABLE_COLUMN_METADATA
static bool bFirst = true;
// Reset the query to use it again if (bFirst)
query.reset(); {
std::cout << "SQLite statement '" << query.getQuery().c_str() << "' reseted (" << query.getColumnCount () << " columns in the result)\n"; // Show how to get the name of a column.
// Bind the string value "6" to the first parameter of the SQL query // Requires the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro to be also defined at compile times of the SQLite library.
query.bind(1, "6"); std::string name0 = query.getColumn(0).getName();
std::cout << "binded with string value \"6\" :\n"; std::string name1 = query.getColumn(1).getName();
std::string name2 = query.getColumn(2).getName();
while (query.executeStep()) std::cout << "table 'test' [\"" << name0.c_str() << "\", \"" << name1.c_str() << "\", \"" << name2.c_str() << "\"]\n";
{ bFirst = false;
// Demonstrate that inserting column value in a std:ostream is natural }
std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\", " << query.getColumn(2) << ")\n"; #endif
} std::cout << "row (" << id << ", \"" << value2.c_str() << "\" " << bytes << " bytes, " << weight << ")\n";
} }
catch (std::exception& e)
{ // Reset the query to use it again
std::cout << "SQLite exception: " << e.what() << std::endl; query.reset();
return EXIT_FAILURE; // unexpected error : exit the example program std::cout << "SQLite statement '" << query.getQuery().c_str() << "' reseted (" << query.getColumnCount () << " columns in the result)\n";
} // Bind the string value "6" to the first parameter of the SQL query
query.bind(1, "6");
//////////////////////////////////////////////////////////////////////////// std::cout << "binded with string value \"6\" :\n";
// Object Oriented Basic example (2/6) :
try while (query.executeStep())
{ {
// Open the database and compile the query // Demonstrate that inserting column value in a std:ostream is natural
Example example; std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\", " << query.getColumn(2) << ")\n";
}
// Demonstrate the way to use the same query with different parameter values }
example.ListGreaterThan(8); catch (std::exception& e)
example.ListGreaterThan(6); {
example.ListGreaterThan(2); std::cout << "SQLite exception: " << e.what() << std::endl;
} return EXIT_FAILURE; // unexpected error : exit the example program
catch (std::exception& e) }
{
std::cout << "SQLite exception: " << e.what() << std::endl; ////////////////////////////////////////////////////////////////////////////
return EXIT_FAILURE; // unexpected error : exit the example program // Object Oriented Basic example (2/6) :
} try
{
// The execAndGet wrapper example (3/6) : // Open the database and compile the query
try Example example;
{
// Open a database file in readonly mode // Demonstrate the way to use the same query with different parameter values
SQLite::Database db(filename_example_db3); // SQLITE_OPEN_READONLY example.ListGreaterThan(8);
std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n"; example.ListGreaterThan(6);
example.ListGreaterThan(2);
// WARNING: Be very careful with this dangerous method: you have to }
// make a COPY OF THE result, else it will be destroy before the next line catch (std::exception& e)
// (when the underlying temporary Statement and Column objects are destroyed) {
std::string value = db.execAndGet("SELECT value FROM test WHERE id=2"); std::cout << "SQLite exception: " << e.what() << std::endl;
std::cout << "execAndGet=" << value.c_str() << std::endl; return EXIT_FAILURE; // unexpected error : exit the example program
} }
catch (std::exception& e)
{ // The execAndGet wrapper example (3/6) :
std::cout << "SQLite exception: " << e.what() << std::endl; try
return EXIT_FAILURE; // unexpected error : exit the example program {
} // Open a database file in readonly mode
SQLite::Database db(filename_example_db3); // SQLITE_OPEN_READONLY
//////////////////////////////////////////////////////////////////////////// std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";
// Simple batch queries example (4/6) :
try // WARNING: Be very careful with this dangerous method: you have to
{ // make a COPY OF THE result, else it will be destroy before the next line
// Open a database file in create/write mode // (when the underlying temporary Statement and Column objects are destroyed)
SQLite::Database db("test.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); std::string value = db.execAndGet("SELECT value FROM test WHERE id=2");
std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n"; std::cout << "execAndGet=" << value.c_str() << std::endl;
}
db.exec("DROP TABLE IF EXISTS test"); catch (std::exception& e)
{
db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"); std::cout << "SQLite exception: " << e.what() << std::endl;
return EXIT_FAILURE; // unexpected error : exit the example program
// first row }
int nb = db.exec("INSERT INTO test VALUES (NULL, \"test\")");
std::cout << "INSERT INTO test VALUES (NULL, \"test\")\", returned " << nb << std::endl; ////////////////////////////////////////////////////////////////////////////
// Simple batch queries example (4/6) :
// second row try
nb = db.exec("INSERT INTO test VALUES (NULL, \"second\")"); {
std::cout << "INSERT INTO test VALUES (NULL, \"second\")\", returned " << nb << std::endl; // Open a database file in create/write mode
SQLite::Database db("test.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
// update the second row std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";
nb = db.exec("UPDATE test SET value=\"second-updated\" WHERE id='2'");
std::cout << "UPDATE test SET value=\"second-updated\" WHERE id='2', returned " << nb << std::endl; db.exec("DROP TABLE IF EXISTS test");
// Check the results : expect two row of result db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");
SQLite::Statement query(db, "SELECT * FROM test");
std::cout << "SELECT * FROM test :\n"; // first row
while (query.executeStep()) int nb = db.exec("INSERT INTO test VALUES (NULL, \"test\")");
{ std::cout << "INSERT INTO test VALUES (NULL, \"test\")\", returned " << nb << std::endl;
std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\")\n";
} // second row
nb = db.exec("INSERT INTO test VALUES (NULL, \"second\")");
db.exec("DROP TABLE test"); std::cout << "INSERT INTO test VALUES (NULL, \"second\")\", returned " << nb << std::endl;
}
catch (std::exception& e) // update the second row
{ nb = db.exec("UPDATE test SET value=\"second-updated\" WHERE id='2'");
std::cout << "SQLite exception: " << e.what() << std::endl; std::cout << "UPDATE test SET value=\"second-updated\" WHERE id='2', returned " << nb << std::endl;
return EXIT_FAILURE; // unexpected error : exit the example program
} // Check the results : expect two row of result
remove("test.db3"); SQLite::Statement query(db, "SELECT * FROM test");
std::cout << "SELECT * FROM test :\n";
//////////////////////////////////////////////////////////////////////////// while (query.executeStep())
// RAII transaction example (5/6) : {
try std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\")\n";
{ }
// Open a database file in create/write mode
SQLite::Database db("transaction.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); db.exec("DROP TABLE test");
std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n"; }
catch (std::exception& e)
db.exec("DROP TABLE IF EXISTS test"); {
std::cout << "SQLite exception: " << e.what() << std::endl;
// Exemple of a successful transaction : return EXIT_FAILURE; // unexpected error : exit the example program
try }
{ remove("test.db3");
// Begin transaction
SQLite::Transaction transaction(db); ////////////////////////////////////////////////////////////////////////////
// RAII transaction example (5/6) :
db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"); try
{
int nb = db.exec("INSERT INTO test VALUES (NULL, \"test\")"); // Open a database file in create/write mode
std::cout << "INSERT INTO test VALUES (NULL, \"test\")\", returned " << nb << std::endl; SQLite::Database db("transaction.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";
// Commit transaction
transaction.commit(); db.exec("DROP TABLE IF EXISTS test");
}
catch (std::exception& e) // Exemple of a successful transaction :
{ try
std::cout << "SQLite exception: " << e.what() << std::endl; {
return EXIT_FAILURE; // unexpected error : exit the example program // Begin transaction
} SQLite::Transaction transaction(db);
// Exemple of a rollbacked transaction : db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");
try
{ int nb = db.exec("INSERT INTO test VALUES (NULL, \"test\")");
// Begin transaction std::cout << "INSERT INTO test VALUES (NULL, \"test\")\", returned " << nb << std::endl;
SQLite::Transaction transaction(db);
// Commit transaction
int nb = db.exec("INSERT INTO test VALUES (NULL, \"second\")"); transaction.commit();
std::cout << "INSERT INTO test VALUES (NULL, \"second\")\", returned " << nb << std::endl; }
catch (std::exception& e)
nb = db.exec("INSERT INTO test ObviousError"); {
std::cout << "INSERT INTO test \"error\", returned " << nb << std::endl; std::cout << "SQLite exception: " << e.what() << std::endl;
return EXIT_FAILURE; // unexpected error : exit the example program
return EXIT_FAILURE; // unexpected success : exit the example program }
// Commit transaction // Exemple of a rollbacked transaction :
transaction.commit(); try
} {
catch (std::exception& e) // Begin transaction
{ SQLite::Transaction transaction(db);
std::cout << "SQLite exception: " << e.what() << std::endl;
// expected error, see above int nb = db.exec("INSERT INTO test VALUES (NULL, \"second\")");
} std::cout << "INSERT INTO test VALUES (NULL, \"second\")\", returned " << nb << std::endl;
// Check the results (expect only one row of result, as the second one has been rollbacked by the error) nb = db.exec("INSERT INTO test ObviousError");
SQLite::Statement query(db, "SELECT * FROM test"); std::cout << "INSERT INTO test \"error\", returned " << nb << std::endl;
std::cout << "SELECT * FROM test :\n";
while (query.executeStep()) return EXIT_FAILURE; // unexpected success : exit the example program
{
std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\")\n"; // Commit transaction
} transaction.commit();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
std::cout << "SQLite exception: " << e.what() << std::endl; std::cout << "SQLite exception: " << e.what() << std::endl;
return EXIT_FAILURE; // unexpected error : exit the example program // expected error, see above
} }
remove("transaction.db3");
// Check the results (expect only one row of result, as the second one has been rollbacked by the error)
//////////////////////////////////////////////////////////////////////////// SQLite::Statement query(db, "SELECT * FROM test");
// Binary blob and in-memory database example (6/6) : std::cout << "SELECT * FROM test :\n";
try while (query.executeStep())
{ {
// Open a database file in create/write mode std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\")\n";
SQLite::Database db(":memory:", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); }
std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n"; }
catch (std::exception& e)
db.exec("DROP TABLE IF EXISTS test"); {
db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value BLOB)"); std::cout << "SQLite exception: " << e.what() << std::endl;
return EXIT_FAILURE; // unexpected error : exit the example program
FILE* fp = fopen(filename_logo_png, "rb"); }
if (NULL != fp) remove("transaction.db3");
{
char buffer[16*1024]; ////////////////////////////////////////////////////////////////////////////
void* blob = &buffer; // Binary blob and in-memory database example (6/6) :
int size = static_cast<int>(fread(blob, 1, 16*1024, fp)); try
buffer[size] = '\0'; {
fclose (fp); // Open a database file in create/write mode
std::cout << "blob size=" << size << " :\n"; SQLite::Database db(":memory:", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";
// Insert query
SQLite::Statement query(db, "INSERT INTO test VALUES (NULL, ?)"); db.exec("DROP TABLE IF EXISTS test");
// Bind the blob value to the first parameter of the SQL query db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value BLOB)");
query.bind(1, blob, size);
std::cout << "blob binded successfully\n"; FILE* fp = fopen(filename_logo_png, "rb");
if (NULL != fp)
// Execute the one-step query to insert the blob {
int nb = query.exec (); char buffer[16*1024];
std::cout << "INSERT INTO test VALUES (NULL, ?)\", returned " << nb << std::endl; void* blob = &buffer;
} int size = static_cast<int>(fread(blob, 1, 16*1024, fp));
else buffer[size] = '\0';
{ fclose (fp);
std::cout << "file " << filename_logo_png << " not found !\n"; std::cout << "blob size=" << size << " :\n";
return EXIT_FAILURE; // unexpected error : exit the example program
} // Insert query
SQLite::Statement query(db, "INSERT INTO test VALUES (NULL, ?)");
fp = fopen("out.png", "wb"); // Bind the blob value to the first parameter of the SQL query
if (NULL != fp) query.bind(1, blob, size);
{ std::cout << "blob binded successfully\n";
const void* blob = NULL;
size_t size; // Execute the one-step query to insert the blob
int nb = query.exec ();
SQLite::Statement query(db, "SELECT * FROM test"); std::cout << "INSERT INTO test VALUES (NULL, ?)\", returned " << nb << std::endl;
std::cout << "SELECT * FROM test :\n"; }
if (query.executeStep()) else
{ {
SQLite::Column colBlob = query.getColumn(1); std::cout << "file " << filename_logo_png << " not found !\n";
blob = colBlob.getBlob (); return EXIT_FAILURE; // unexpected error : exit the example program
size = colBlob.getBytes (); }
std::cout << "row (" << query.getColumn(0) << ", size=" << size << ")\n";
size_t sizew = fwrite(blob, 1, size, fp); fp = fopen("out.png", "wb");
SQLITE_CPP_ASSERT(sizew == size); if (NULL != fp)
fclose (fp); {
} const void* blob = NULL;
} size_t size;
else
{ SQLite::Statement query(db, "SELECT * FROM test");
std::cout << "file out.png not created !\n"; std::cout << "SELECT * FROM test :\n";
return EXIT_FAILURE; // unexpected error : exit the example program if (query.executeStep())
} {
} SQLite::Column colBlob = query.getColumn(1);
catch (std::exception& e) blob = colBlob.getBlob ();
{ size = colBlob.getBytes ();
std::cout << "SQLite exception: " << e.what() << std::endl; std::cout << "row (" << query.getColumn(0) << ", size=" << size << ")\n";
return EXIT_FAILURE; // unexpected error : exit the example program size_t sizew = fwrite(blob, 1, size, fp);
} SQLITECPP_ASSERT(sizew == size, "fwrite failed"); // See SQLITECPP_ENABLE_ASSERT_HANDLER
remove("out.png"); fclose (fp);
}
std::cout << "everything ok, quitting\n"; }
else
return EXIT_SUCCESS; {
} std::cout << "file out.png not created !\n";
return EXIT_FAILURE; // unexpected error : exit the example program
}
}
catch (std::exception& e)
{
std::cout << "SQLite exception: " << e.what() << std::endl;
return EXIT_FAILURE; // unexpected error : exit the example program
}
remove("out.png");
std::cout << "everything ok, quitting\n";
return EXIT_SUCCESS;
}

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);
} }
} }
} }