diff --git a/include/SQLiteCpp/Column.h b/include/SQLiteCpp/Column.h index 9d1ce25..1301205 100644 --- a/include/SQLiteCpp/Column.h +++ b/include/SQLiteCpp/Column.h @@ -104,7 +104,6 @@ public: * @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 diff --git a/include/SQLiteCpp/Statement.h b/include/SQLiteCpp/Statement.h index e4dad53..95b5d05 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -139,12 +139,16 @@ public: /** * @brief Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1). * + * The string can contain null characters as it is binded using its size. + * * @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) * + * Main usage is with null-terminated literal text (aka in code static strings) + * * @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); @@ -198,12 +202,16 @@ public: /** * @brief Bind a string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) * + * The string can contain null characters as it is binded using its size. + * * @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) * + * Main usage is with null-terminated literal text (aka in code static strings) + * * @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); @@ -279,6 +287,8 @@ public: /** * @brief Bind a string value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) * + * The string can contain null characters as it is binded using its size. + * * @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) @@ -288,6 +298,8 @@ public: /** * @brief Bind a text value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1) * + * Main usage is with null-terminated literal text (aka in code static strings) + * * @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) diff --git a/tests/Statement_test.cpp b/tests/Statement_test.cpp index 65790e2..ca99b2b 100644 --- a/tests/Statement_test.cpp +++ b/tests/Statement_test.cpp @@ -282,6 +282,45 @@ TEST(Statement, bindings) { } } +TEST(Statement, bindNoCopy) { + // Create a new database + SQLite::Database db(":memory:", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + EXPECT_EQ(SQLITE_OK, db.getErrorCode()); + + // Create a new table + EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, txt1 TEXT, txt2 TEXT, binary BLOB)")); + EXPECT_EQ(SQLITE_OK, db.getErrorCode()); + + // Insertion with bindable parameters + SQLite::Statement insert(db, "INSERT INTO test VALUES (NULL, ?, ?, ?)"); + + // Compile a SQL query to check the results + SQLite::Statement query(db, "SELECT * FROM test"); + EXPECT_STREQ("SELECT * FROM test", query.getQuery().c_str()); + EXPECT_EQ(4, query.getColumnCount()); + + // Insert one row with all variants of bindNoCopy() + { + const char* txt1 = "first"; + const std::string txt2 = "sec\0nd"; + const char blob[] = {'b','l','\0','b'}; + insert.bindNoCopy(1, txt1); + insert.bindNoCopy(2, txt2); + insert.bindNoCopy(3, blob, sizeof(blob)); + EXPECT_EQ(1, insert.exec()); + EXPECT_EQ(SQLITE_DONE, db.getErrorCode()); + + // Check the first row + query.executeStep(); + EXPECT_TRUE(query.isOk()); + EXPECT_FALSE(query.isDone()); + EXPECT_EQ(1, query.getColumn(0).getInt64()); + EXPECT_STREQ(txt1, query.getColumn(1).getText()); + EXPECT_EQ(0, memcmp(&txt2[0], &query.getColumn(2).getString()[0], txt2.size())); + EXPECT_EQ(0, memcmp(blob, &query.getColumn(3).getString()[0], sizeof(blob))); + } +} + TEST(Statement, bindByName) { // Create a new database SQLite::Database db(":memory:", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);