diff --git a/include/SQLiteCpp/Column.h b/include/SQLiteCpp/Column.h index 7a74fd8..2d8e47b 100644 --- a/include/SQLiteCpp/Column.h +++ b/include/SQLiteCpp/Column.h @@ -99,6 +99,13 @@ 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 { @@ -193,12 +205,19 @@ public: // 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..d1a8597 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -80,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) @@ -101,74 +101,123 @@ 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 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) */ - 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 + * @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); + void bind(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); + 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); + 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) + * + * @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); /** * @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); /** * @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 + * @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 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) + * + * @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); /** * @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 @@ -176,28 +225,35 @@ 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); } /** * @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) { @@ -206,7 +262,7 @@ public: /** * @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) { @@ -215,14 +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) + * + * @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) + { + 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/Column.cpp b/src/Column.cpp index 2545864..1503039 100644 --- a/src/Column.cpp +++ b/src/Column.cpp @@ -11,6 +11,7 @@ #include #include +#include namespace SQLite @@ -69,12 +70,24 @@ 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)); + + // 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..3788734 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -43,6 +43,7 @@ Statement::Statement(Database &aDatabase, const std::string& aQuery) : mColumnCount = sqlite3_column_count(mStmtPtr); } + // Finalize and unregister the SQL query from the SQLite Database Connection. Statement::~Statement() noexcept // nothrow { @@ -66,21 +67,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); @@ -108,6 +116,28 @@ 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) +{ + 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 +147,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 +155,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 +171,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); @@ -165,6 +203,31 @@ 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) +{ + 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) {