diff --git a/include/SQLiteCpp/Column.h b/include/SQLiteCpp/Column.h index 7a74fd8..7e1da29 100644 --- a/include/SQLiteCpp/Column.h +++ b/include/SQLiteCpp/Column.h @@ -99,7 +99,14 @@ public: * thus you must copy it before using it beyond its scope (to a std::string for instance). */ const void* getBlob() const noexcept; // nothrow - + /** + * @brief Return a std::string for a TEXT or BLOB column. + * + * Note this correctly handles strings that contain null bytes. + * + */ + std::string getString() const noexcept; // nothrow + /** * @brief Return the type of the value of the column * @@ -158,6 +165,11 @@ public: { return getInt(); } + /// @brief Inline cast operator to 32bits unsigned integer + inline operator uint32_t() const + { + return static_cast(getInt64()); + } /// @brief Inline cast operator to 64bits integer inline operator sqlite3_int64() const { @@ -186,19 +198,26 @@ public: { return getBlob(); } - + #if !(defined(_MSC_VER) && _MSC_VER < 1900) // NOTE : the following is required by GCC and Clang to cast a Column result in a std::string // (error: conversion from ‘SQLite::Column’ to non-scalar type ‘std::string {aka std::basic_string}’) // but is not working under Microsoft Visual Studio 2010, 2012 and 2013 // (error C2440: 'initializing' : cannot convert from 'SQLite::Column' to 'std::basic_string<_Elem,_Traits,_Ax>' // [...] constructor overload resolution was ambiguous) - /// Inline cast operator to std::string - inline operator const std::string() const + /** + * @brief Inline cast operator to std::string + * + * Handles BLOB or TEXT, which may contain null bytes within + * + * @see getString + */ + inline operator std::string() const { - return getText(); + return getString(); } #endif + // NOTE : the following is required by GCC and Clang to cast a Column result in a long/int64_t /// @brief Inline cast operator to long as 64bits integer inline operator long() const diff --git a/include/SQLiteCpp/Statement.h b/include/SQLiteCpp/Statement.h index dc44b6e..8da3f74 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -67,6 +67,17 @@ public: */ Statement(Database& aDatabase, const std::string& aQuery); + // Require C++11 +#if ( __cplusplus>= 201103L) || ( defined(_MSC_VER) && (_MSC_VER >= 1900) ) + #define Statement_CAN_MOVE 1 + /** + * @breif Move Constructor + * + * (Allows inserting into STL containers that may need to move memory when growing.) + */ + Statement(Statement &&other); +#endif + /** * @brief Finalize and unregister the SQL query from the SQLite Database Connection. */ @@ -105,21 +116,33 @@ public: /** * @brief Bind an int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ - void bind(const int aIndex, const int& aValue); + void bind(const int aIndex, const int aValue); /** * @brief Bind a 64bits int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ - void bind(const int aIndex, const sqlite3_int64& aValue); + void bind(const int aIndex, const sqlite3_int64 aValue); + /** + * @brief Bind a 32bits unsigned int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + */ + void bind(const int aIndex, const uint32_t aValue); /** * @brief Bind a double (64bits float) value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ - void bind(const int aIndex, const double& aValue); + void bind(const int aIndex, const double aValue); /** * @brief Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) * * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use */ void bind(const int aIndex, const std::string& aValue); + + /** + * @brief Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @note This uses the SQLITE_STATIC flag, NOT making a copy of the data. It must exist while executing the statement. + */ + void bindNoCopy(const int aIndex, const std::string& aValue); + /** * @brief Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) * @@ -132,6 +155,14 @@ public: * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use */ void bind(const int aIndex, const void* apValue, const int aSize); + + /** + * @brief Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @note This uses the SQLITE_STATIC flag, NOT making a copy of the data. It must exist while executing the statement. + */ + void bindNoCopy(const int aIndex, const void* apValue, const int aSize); + /** * @brief Bind a NULL value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ @@ -140,21 +171,31 @@ public: /** * @brief Bind an int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ - void bind(const char* apName, const int& aValue); + void bind(const char* apName, const int aValue); /** * @brief Bind a 64bits int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ - void bind(const char* apName, const sqlite3_int64& aValue); + void bind(const char* apName, const sqlite3_int64 aValue); + /** + * @brief Bind a 32bits unsigned int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + */ + void bind(const char* apName, const uint32_t aValue); /** * @brief Bind a double (64bits float) value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ - void bind(const char* apName, const double& aValue); + void bind(const char* apName, const double aValue); /** * @brief Bind a string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) * * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use */ void bind(const char* apName, const std::string& aValue); + /** + * @brief Bind a string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @note This uses the SQLITE_STATIC flag, NOT making a copy of the data. + */ + void bindNoCopy(const char* apName, const std::string& aValue); /** * @brief Bind a text value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) * @@ -167,6 +208,12 @@ public: * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use */ void bind(const char* apName, const void* apValue, const int aSize); + /** + * @brief Bind a binary blob value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @note This uses the SQLITE_STATIC flag, making a copy of the data. + */ + void bindNoCopy(const char* apName, const void* apValue, const int aSize); /** * @brief Bind a NULL value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ @@ -176,21 +223,28 @@ public: /** * @brief Bind an int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ - inline void bind(const std::string& aName, const int& aValue) + inline void bind(const std::string& aName, const int aValue) { bind(aName.c_str(), aValue); } /** * @brief Bind a 64bits int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ - inline void bind(const std::string& aName, const sqlite3_int64& aValue) + inline void bind(const std::string& aName, const sqlite3_int64 aValue) + { + bind(aName.c_str(), aValue); + } + /** + * @brief Bind a 32bits unsigned int value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + */ + inline void bind(const std::string& aName, const uint32_t aValue) { bind(aName.c_str(), aValue); } /** * @brief Bind a double (64bits float) value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ - inline void bind(const std::string& aName, const double& aValue) + inline void bind(const std::string& aName, const double aValue) { bind(aName.c_str(), aValue); } @@ -203,6 +257,15 @@ public: { bind(aName.c_str(), aValue); } + /** + * @brief Bind a string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @note This uses the SQLITE_STATIC flag, NOT making a copy of the data. + */ + inline void bindNoCopy(const std::string& aName, const std::string& aValue) + { + bindNoCopy(aName.c_str(), aValue); + } /** * @brief Bind a text value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) * @@ -221,6 +284,15 @@ public: { bind(aName.c_str(), apValue, aSize); } + /** + * @brief Bind a binary blob value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @note This uses the SQLITE_STATIC flag, NOT making a copy of the data. + */ + inline void bindNoCopy(const std::string& aName, const void* apValue, const int aSize) + { + bindNoCopy(aName.c_str(), apValue, aSize); + } /** * @brief Bind a NULL value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) */ diff --git a/src/Column.cpp b/src/Column.cpp index 2545864..d4ec564 100644 --- a/src/Column.cpp +++ b/src/Column.cpp @@ -69,12 +69,25 @@ const char* Column::getText(const char* apDefaultValue /* = "" */) const noexcep return (pText?pText:apDefaultValue); } -// Return a pointer to the text value (NULL terminated string) of the column specified by its index starting at 0 +// Return a pointer to the blob value (*not* NULL terminated) of the column specified by its index starting at 0 const void* Column::getBlob() const noexcept // nothrow { return sqlite3_column_blob(mStmtPtr, mIndex); } +// Return a std::string to a TEXT or BLOB column +std::string Column::getString() const noexcept // nothrow +{ + // Note: using sqlite3_column_blob and not sqlite3_column_text + // - no need for sqlite3_column_text to add a \0 on the end, as we're getting the bytes length directly + const char *data = static_cast(sqlite3_column_blob(mStmtPtr, mIndex)); + + // Note: C++ order of argument evaluation is unspecified, so not calling _blob and _bytes both directly in std::string constructor + // SQLite docs: "The safest policy is to invoke… sqlite3_column_blob() followed by sqlite3_column_bytes()" + // Note: std::string is ok to pass nullptr as first arg, if length is 0 + return std::string(data, sqlite3_column_bytes(mStmtPtr, mIndex)); +} + // Return the type of the value of the column int Column::getType() const noexcept // nothrow { diff --git a/src/Statement.cpp b/src/Statement.cpp index 64488e4..f94c06a 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -43,6 +43,23 @@ Statement::Statement(Database &aDatabase, const std::string& aQuery) : mColumnCount = sqlite3_column_count(mStmtPtr); } +#ifdef Statement_CAN_MOVE +// Move Constructor +Statement::Statement(Statement &&other): +mQuery(std::move(other.mQuery)), +mStmtPtr(other.mStmtPtr), +mColumnCount(other.mColumnCount), +mColumnNames(std::move(other.mColumnNames)), +mbOk(other.mbOk), +mbDone(other.mbDone) +{ + //other.mStmtPtr = nullptr; // doesn't support reassigning + other.mColumnCount = 0; + other.mbOk = false; + other.mbDone = false; +} +#endif + // Finalize and unregister the SQL query from the SQLite Database Connection. Statement::~Statement() noexcept // nothrow { @@ -66,21 +83,28 @@ void Statement::clearBindings() } // Bind an int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement -void Statement::bind(const int aIndex, const int& aValue) +void Statement::bind(const int aIndex, const int aValue) { const int ret = sqlite3_bind_int(mStmtPtr, aIndex, aValue); check(ret); } // Bind a 64bits int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement -void Statement::bind(const int aIndex, const sqlite3_int64& aValue) +void Statement::bind(const int aIndex, const sqlite3_int64 aValue) +{ + const int ret = sqlite3_bind_int64(mStmtPtr, aIndex, aValue); + check(ret); +} + +// Bind a 32bits unsigned int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement +void Statement::bind(const int aIndex, const uint32_t aValue) { const int ret = sqlite3_bind_int64(mStmtPtr, aIndex, aValue); check(ret); } // Bind a double (64bits float) value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement -void Statement::bind(const int aIndex, const double& aValue) +void Statement::bind(const int aIndex, const double aValue) { const int ret = sqlite3_bind_double(mStmtPtr, aIndex, aValue); check(ret); @@ -93,6 +117,14 @@ void Statement::bind(const int aIndex, const std::string& aValue) static_cast(aValue.size()), SQLITE_TRANSIENT); check(ret); } + +// Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement +void Statement::bindNoCopy(const int aIndex, const std::string& aValue) +{ + const int ret = sqlite3_bind_text(mStmtPtr, aIndex, aValue.c_str(), + static_cast(aValue.size()), SQLITE_STATIC); + check(ret); +} // Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const int aIndex, const char* apValue) @@ -108,6 +140,13 @@ void Statement::bind(const int aIndex, const void* apValue, const int aSize) check(ret); } +// Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement +void Statement::bindNoCopy(const int aIndex, const void* apValue, const int aSize) +{ + const int ret = sqlite3_bind_blob(mStmtPtr, aIndex, apValue, aSize, SQLITE_STATIC); + check(ret); +} + // Bind a NULL value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const int aIndex) { @@ -117,7 +156,7 @@ void Statement::bind(const int aIndex) // Bind an int value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement -void Statement::bind(const char* apName, const int& aValue) +void Statement::bind(const char* apName, const int aValue) { const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); const int ret = sqlite3_bind_int(mStmtPtr, index, aValue); @@ -125,7 +164,15 @@ void Statement::bind(const char* apName, const int& aValue) } // Bind a 64bits int value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement -void Statement::bind(const char* apName, const sqlite3_int64& aValue) +void Statement::bind(const char* apName, const sqlite3_int64 aValue) +{ + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_int64(mStmtPtr, index, aValue); + check(ret); +} + +// Bind a 32bits unsigned int value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement +void Statement::bind(const char* apName, const uint32_t aValue) { const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); const int ret = sqlite3_bind_int64(mStmtPtr, index, aValue); @@ -133,7 +180,7 @@ void Statement::bind(const char* apName, const sqlite3_int64& aValue) } // Bind a double (64bits float) value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement -void Statement::bind(const char* apName, const double& aValue) +void Statement::bind(const char* apName, const double aValue) { const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); const int ret = sqlite3_bind_double(mStmtPtr, index, aValue); @@ -149,6 +196,15 @@ void Statement::bind(const char* apName, const std::string& aValue) check(ret); } +// Bind a string value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement +void Statement::bindNoCopy(const char* apName, const std::string& aValue) +{ + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_text(mStmtPtr, index, aValue.c_str(), + static_cast(aValue.size()), SQLITE_STATIC); + check(ret); +} + // Bind a text value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const char* apName, const char* apValue) { @@ -165,6 +221,14 @@ void Statement::bind(const char* apName, const void* apValue, const int aSize) check(ret); } +// Bind a binary blob value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement +void Statement::bindNoCopy(const char* apName, const void* apValue, const int aSize) +{ + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_blob(mStmtPtr, index, apValue, aSize, SQLITE_STATIC); + check(ret); +} + // Bind a NULL value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement void Statement::bind(const char* apName) {