From a84c04aada9ace6efb54373ab792cb27dae7125d Mon Sep 17 00:00:00 2001 From: Douglas Heriot Date: Sat, 25 Jun 2016 16:22:03 +1000 Subject: [PATCH 1/5] Add bindNoCopy methods to allow binding std::string with SQLITE_STATIC. Should be safe, as long as you can guarantee the std::string exists while executing the query. Added an accessor to Column that returns a std::string, that can handle BLOB or TEXT values that contain null-bytes. Also more binding & Column cast support for uint32_t - fixes ambiguous overload errors when using unsigned-integer types. Note that I didn't use uint64_t, because unsigned 64-bit integers doesn't fit into SQLite (except for using int64_t and dealing with overflow with custom functions). Added a C++11 move constructor to Statement, to allow storing it inside STL containers (eg. vector). --- include/SQLiteCpp/Column.h | 29 +++++++++-- include/SQLiteCpp/Statement.h | 90 +++++++++++++++++++++++++++++++---- src/Column.cpp | 15 +++++- src/Statement.cpp | 76 ++++++++++++++++++++++++++--- 4 files changed, 189 insertions(+), 21 deletions(-) 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) { From 9a07f3918dcb4016a808631bd05d2dd6c5e96cec Mon Sep 17 00:00:00 2001 From: Douglas Heriot Date: Sun, 26 Jun 2016 01:58:01 +1000 Subject: [PATCH 2/5] Fix build on Linux, including cpplint warnings. --- include/SQLiteCpp/Column.h | 6 +++--- include/SQLiteCpp/Statement.h | 9 +++++---- src/Column.cpp | 4 ++-- src/Statement.cpp | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/SQLiteCpp/Column.h b/include/SQLiteCpp/Column.h index 7e1da29..2d8e47b 100644 --- a/include/SQLiteCpp/Column.h +++ b/include/SQLiteCpp/Column.h @@ -106,7 +106,7 @@ public: * */ std::string getString() const noexcept; // nothrow - + /** * @brief Return the type of the value of the column * @@ -198,7 +198,7 @@ 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}’) @@ -217,7 +217,7 @@ public: 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 8da3f74..9cd8458 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -135,14 +136,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 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) * @@ -155,14 +156,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) */ diff --git a/src/Column.cpp b/src/Column.cpp index d4ec564..1503039 100644 --- a/src/Column.cpp +++ b/src/Column.cpp @@ -11,6 +11,7 @@ #include #include +#include namespace SQLite @@ -81,8 +82,7 @@ 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)); diff --git a/src/Statement.cpp b/src/Statement.cpp index f94c06a..1074f26 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -53,7 +53,7 @@ mColumnNames(std::move(other.mColumnNames)), mbOk(other.mbOk), mbDone(other.mbDone) { - //other.mStmtPtr = nullptr; // doesn't support reassigning + // other.mStmtPtr = nullptr; // doesn't support reassigning other.mColumnCount = 0; other.mbOk = false; other.mbDone = false; @@ -117,7 +117,7 @@ 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) { From bcdbea2cf84b89c8eaa51f805d05fda3651df13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Sat, 2 Jul 2016 14:11:02 +0200 Subject: [PATCH 3/5] Style cleanup on top of PR #86 --- include/SQLiteCpp/Statement.h | 35 ++++++++++++++++++----------------- src/Statement.cpp | 16 ++++++++-------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/include/SQLiteCpp/Statement.h b/include/SQLiteCpp/Statement.h index 9cd8458..0d7bd7c 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -68,15 +68,15 @@ 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 +#if (__cplusplus >= 201103L) || ( defined(_MSC_VER) && (_MSC_VER >= 1600) ) // C++11: Visual Studio 2010 /** - * @breif Move Constructor + * @brief Move Constructor * - * (Allows inserting into STL containers that may need to move memory when growing.) + * Allows inserting into STL containers that may need to move memory when growing. + * + * @param aOther Statement to move to */ - Statement(Statement &&other); + Statement(Statement&& aOther); #endif /** @@ -113,6 +113,7 @@ public: // This is under-optimized for static data (a static text define in code) // as well as for dynamic allocated buffer which could be transfer to sqlite // instead of being copied. + // => if you now what you are doing, use bindNoCopy() /** * @brief Bind an int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) @@ -125,7 +126,7 @@ public: /** * @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); + 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) */ @@ -135,34 +136,34 @@ public: * * @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); + 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. + * @note This uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement. */ - void bindNoCopy(const int aIndex, const std::string& aValue); + 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) * * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use */ - void bind(const int aIndex, const char* apValue); + void bind(const int aIndex, const char* apValue); /** * @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_TRANSIENT flag, making a copy of the data, for SQLite internal use */ - void bind(const int aIndex, const void* apValue, const int aSize); + 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); + 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) @@ -172,19 +173,19 @@ 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); + 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) * diff --git a/src/Statement.cpp b/src/Statement.cpp index 1074f26..f83f00f 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -43,15 +43,15 @@ Statement::Statement(Database &aDatabase, const std::string& aQuery) : mColumnCount = sqlite3_column_count(mStmtPtr); } -#ifdef Statement_CAN_MOVE +#if (__cplusplus >= 201103L) || ( defined(_MSC_VER) && (_MSC_VER >= 1600) ) // C++11: Visual Studio 2010 // 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) +Statement::Statement(Statement&& aOther): + mQuery(std::move(aOther.mQuery)), + mStmtPtr(aOther.mStmtPtr), // TODO: need a move operator + mColumnCount(aOther.mColumnCount), + mColumnNames(std::move(aOther.mColumnNames)), + mbOk(aOther.mbOk), + mbDone(aOther.mbDone) { // other.mStmtPtr = nullptr; // doesn't support reassigning other.mColumnCount = 0; From e7384b30a827fef4024315dd92d2a42e00a6658e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Sat, 2 Jul 2016 14:12:35 +0200 Subject: [PATCH 4/5] Remove unfinished Statement move constructor from PR #86 - see comments in code: needs a move constructor on Statement::Ptr --- include/SQLiteCpp/Statement.h | 11 ----------- src/Statement.cpp | 16 ---------------- 2 files changed, 27 deletions(-) diff --git a/include/SQLiteCpp/Statement.h b/include/SQLiteCpp/Statement.h index 0d7bd7c..7a03ffa 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -68,17 +68,6 @@ public: */ Statement(Database& aDatabase, const std::string& aQuery); -#if (__cplusplus >= 201103L) || ( defined(_MSC_VER) && (_MSC_VER >= 1600) ) // C++11: Visual Studio 2010 - /** - * @brief Move Constructor - * - * Allows inserting into STL containers that may need to move memory when growing. - * - * @param aOther Statement to move to - */ - Statement(Statement&& aOther); -#endif - /** * @brief Finalize and unregister the SQL query from the SQLite Database Connection. */ diff --git a/src/Statement.cpp b/src/Statement.cpp index f83f00f..98db9ec 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -43,22 +43,6 @@ Statement::Statement(Database &aDatabase, const std::string& aQuery) : mColumnCount = sqlite3_column_count(mStmtPtr); } -#if (__cplusplus >= 201103L) || ( defined(_MSC_VER) && (_MSC_VER >= 1600) ) // C++11: Visual Studio 2010 -// Move Constructor -Statement::Statement(Statement&& aOther): - mQuery(std::move(aOther.mQuery)), - mStmtPtr(aOther.mStmtPtr), // TODO: need a move operator - mColumnCount(aOther.mColumnCount), - mColumnNames(std::move(aOther.mColumnNames)), - mbOk(aOther.mbOk), - mbDone(aOther.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 From 9c03f4e86bb1f360bd88d7b21f7cef1baae19f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Sun, 3 Jul 2016 16:55:27 +0200 Subject: [PATCH 5/5] Add bindNoCopy() for C-style null-terminated text strings --- include/SQLiteCpp/Statement.h | 108 ++++++++++++++++++++-------------- src/Statement.cpp | 49 +++++++++------ 2 files changed, 97 insertions(+), 60 deletions(-) diff --git a/include/SQLiteCpp/Statement.h b/include/SQLiteCpp/Statement.h index 7a03ffa..d1a8597 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -81,8 +81,7 @@ public: /** * @brief Clears away all the bindings of a prepared statement. * - * Contrary to the intuition of many, reset() does not reset - * the bindings on a prepared statement. + * Contrary to the intuition of many, reset() does not reset the bindings on a prepared statement. * Use this routine to reset all parameters to NULL. */ void clearBindings(); // throw(SQLite::Exception) @@ -102,7 +101,7 @@ public: // This is under-optimized for static data (a static text define in code) // as well as for dynamic allocated buffer which could be transfer to sqlite // instead of being copied. - // => if you now what you are doing, use bindNoCopy() + // => if you know what you are doing, use bindNoCopy() instead of bind() /** * @brief Bind an int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) @@ -123,39 +122,43 @@ public: /** * @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 + * @note 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, avoiding a copy of the data. The string must remains unchanged 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) * - * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use + * @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use */ void bind(const int aIndex, const char* apValue); /** * @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_TRANSIENT flag, making a copy of the data, for SQLite internal use + * @note 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 string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1). + * + * @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged 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) + * + * @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement. + */ + void bindNoCopy(const int aIndex, const char* apValue); /** * @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. + * @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement. */ - void bindNoCopy(const int aIndex, const void* apValue, const int aSize); - + 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) + * + * @see clearBindings() to set all bound parameters to NULL. */ void bind(const int aIndex); @@ -178,35 +181,43 @@ public: /** * @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 + * @note 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) * - * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use + * @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use */ void bind(const char* apName, const char* apValue); /** * @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_TRANSIENT flag, making a copy of the data, for SQLite internal use + * @note 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 string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement. + */ + 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) + * + * @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement. + */ + void bindNoCopy(const char* apName, const char* apValue); /** * @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. + * @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement. */ - void bindNoCopy(const char* apName, const void* apValue, const int aSize); + 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) + * + * @see clearBindings() to set all bound parameters to NULL. */ void bind(const char* apName); // bind NULL value @@ -242,25 +253,16 @@ public: /** * @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 + * @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use */ inline void bind(const std::string& aName, const std::string& aValue) { 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) * - * @note This uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use + * @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use */ inline void bind(const std::string& aName, const char* apValue) { @@ -269,23 +271,43 @@ public: /** * @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_TRANSIENT flag, making a copy of the data, for SQLite internal use + * @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use */ inline void bind(const std::string& aName, const void* apValue, const int aSize) { bind(aName.c_str(), apValue, aSize); } + /** + * @brief Bind a string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) + * + * @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement. + */ + 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) + * + * @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement. + */ + inline void bindNoCopy(const std::string& aName, const char* apValue) + { + bindNoCopy(aName.c_str(), apValue); + } /** * @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. + * @warning Uses the SQLITE_STATIC flag, avoiding a copy of the data. The string must remains unchanged while executing the statement. */ - inline void bindNoCopy(const std::string& aName, const void* apValue, const int aSize) + 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) + * + * @see clearBindings() to set all bound parameters to NULL. */ inline void bind(const std::string& aName) // bind NULL value { diff --git a/src/Statement.cpp b/src/Statement.cpp index 98db9ec..3788734 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -102,14 +102,6 @@ void Statement::bind(const int aIndex, 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 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) { @@ -124,6 +116,21 @@ void Statement::bind(const int aIndex, const void* apValue, const int aSize) 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::bindNoCopy(const int aIndex, const char* apValue) +{ + const int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, -1, SQLITE_STATIC); + 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) { @@ -180,15 +187,6 @@ 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) { @@ -205,6 +203,23 @@ void Statement::bind(const char* apName, const void* apValue, const int aSize) 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::bindNoCopy(const char* apName, const char* apValue) +{ + const int index = sqlite3_bind_parameter_index(mStmtPtr, apName); + const int ret = sqlite3_bind_text(mStmtPtr, index, apValue, -1, SQLITE_STATIC); + 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) {