Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added some bindings for std::string_view when using c++17 #224

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 130 additions & 6 deletions include/SQLiteCpp/Statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,16 @@ class Statement
*
* @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, const int aSize);
/**
* @brief Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
*
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
*/
void bind(const int aIndex, const char* apValue)
{
bind(aIndex, apValue, -1);
}
/**
* @brief Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
*
Expand All @@ -186,14 +195,25 @@ class 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 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 text which might not be null-terminated.
*
* @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, const int aSize);
/**
* @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);
inline void bindNoCopy(const int aIndex, const char* apValue)
{
bindNoCopy(aIndex, apValue, -1);
}
/**
* @brief Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
*
Expand Down Expand Up @@ -262,14 +282,23 @@ class Statement
{
bind(getIndex(apName), aValue);
}
/**
* @brief Bind a text value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
*
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
*/
void bind(const char* apName, const char* apValue, const int aSize)
{
bind(getIndex(apName), apValue, aSize);
}
/**
* @brief Bind a text value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
*
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
*/
void bind(const char* apName, const char* apValue)
{
bind(getIndex(apName), apValue);
bind(getIndex(apName), apValue, -1);
}
/**
* @brief Bind a binary blob value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
Expand All @@ -291,6 +320,17 @@ class Statement
{
bindNoCopy(getIndex(apName), 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 text which might not be null-terminated
*
* @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, const int aSize)
{
bindNoCopy(getIndex(apName), apValue, aSize);
}
/**
* @brief Bind a text value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
*
Expand All @@ -300,7 +340,7 @@ class Statement
*/
void bindNoCopy(const char* apName, const char* apValue)
{
bindNoCopy(getIndex(apName), apValue);
bindNoCopy(getIndex(apName), apValue, -1);
}
/**
* @brief Bind a binary blob value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
Expand Down Expand Up @@ -384,7 +424,16 @@ class Statement
*/
void bind(const std::string& aName, const char* apValue)
{
bind(aName.c_str(), apValue);
bind(aName.c_str(), apValue, -1);
}
/**
* @brief Bind a text value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
*
* @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, const int aSize)
{
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)
Expand Down Expand Up @@ -415,7 +464,18 @@ class Statement
*/
void bindNoCopy(const std::string& aName, const char* apValue)
{
bindNoCopy(aName.c_str(), apValue);
bindNoCopy(aName.c_str(), apValue, -1);
}
/**
* @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, const int aSize)
{
bindNoCopy(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)
Expand All @@ -436,6 +496,70 @@ class Statement
bind(aName.c_str());
}

// Provide bindings for std::string_view if using at least c++17
#if __cplusplus >= 201703L
/**
* @brief Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
*
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
*/
inline void bind(const int aIndex, std::string_view aValue)
{
bind(aIndex, aValue.data(), static_cast<int>(aValue.size()));
}
/**
* @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.
*/
inline void bindNoCopy(const int aIndex, std::string_view aValue)
{
bindNoCopy(aIndex, aValue.data(), static_cast<int>(aValue.size()));
}
/**
* @brief Bind a string_view value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
*
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
*/
inline void bind(const char* apName, std::string_view aValue)
{
bind(apName, aValue.data(), static_cast<int>(aValue.size()));
}
/**
* @brief Bind a string_view 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 char* apName, std::string_view aValue)
{
bind(apName, aValue.data(), static_cast<int>(aValue.size()));
}
/**
* @brief Bind a string_view value to a named parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement (aIndex >= 1)
*
* @note Uses the SQLITE_TRANSIENT flag, making a copy of the data, for SQLite internal use
*/
inline void bind(const std::string& aName, std::string_view aValue)
{
bind(aName.c_str(), aValue.data(), static_cast<int>(aValue.size()));
}
/**
* @brief Bind a string_view 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, std::string_view aValue)
{
bindNoCopy(aName.c_str(), aValue.data(), static_cast<int>(aValue.size()));
}
#endif

////////////////////////////////////////////////////////////////////////////

/**
Expand Down
8 changes: 4 additions & 4 deletions src/Statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ void Statement::bind(const int aIndex, const std::string& aValue)
}

// 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)
void Statement::bind(const int aIndex, const char* apValue, const int aSize)
{
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, -1, SQLITE_TRANSIENT);
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, aSize, SQLITE_TRANSIENT);
check(ret);
}

Expand All @@ -127,9 +127,9 @@ void Statement::bindNoCopy(const int aIndex, const std::string& aValue)
}

// 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)
void Statement::bindNoCopy(const int aIndex, const char* apValue, const int aSize)
{
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, -1, SQLITE_STATIC);
const int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, aSize, SQLITE_STATIC);
check(ret);
}

Expand Down
65 changes: 53 additions & 12 deletions tests/Statement_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ TEST(Statement, bindings)

// Fifth row with binary buffer and a null parameter
{
const char buffer[] = "binary";
const unsigned char buffer[] = "binary";
insert.bind(1, buffer, sizeof(buffer));
insert.bind(2);
EXPECT_EQ(1, insert.exec());
Expand All @@ -351,7 +351,7 @@ TEST(Statement, bindings)
EXPECT_TRUE (query.hasRow());
EXPECT_FALSE(query.isDone());
EXPECT_EQ(5, query.getColumn(0).getInt64());
EXPECT_STREQ(buffer, query.getColumn(1).getText());
EXPECT_EQ(0, memcmp(buffer, &query.getColumn(1).getString()[0], sizeof(buffer)));
EXPECT_TRUE (query.isColumnNull(2));
EXPECT_EQ(0, query.getColumn(2).getInt());
EXPECT_EQ(0.234f, query.getColumn(3).getDouble());
Expand Down Expand Up @@ -406,25 +406,26 @@ TEST(Statement, bindNoCopy)
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(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, txt1 TEXT, txt2 TEXT, txt3 TEXT, binary BLOB)"));
EXPECT_EQ(SQLite::OK, db.getErrorCode());

// Insertion with bindable parameters
SQLite::Statement insert(db, "INSERT INTO test VALUES (NULL, ?, ?, ?)");
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());
EXPECT_EQ(5, 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'};
const unsigned char blob[] = {'b','l','\0','b'};
insert.bindNoCopy(1, txt1);
insert.bindNoCopy(2, txt2);
insert.bindNoCopy(3, blob, sizeof(blob));
insert.bindNoCopy(3, txt2.c_str(), static_cast<int>(txt2.size()));
insert.bindNoCopy(4, blob, sizeof(blob));
EXPECT_EQ(1, insert.exec());
EXPECT_EQ(SQLITE_DONE, db.getErrorCode());

Expand All @@ -435,7 +436,8 @@ TEST(Statement, bindNoCopy)
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)));
EXPECT_EQ(0, memcmp(&txt2[0], &query.getColumn(3).getString()[0], txt2.size()));
EXPECT_EQ(0, memcmp(blob, &query.getColumn(4).getString()[0], sizeof(blob)));
}
}

Expand Down Expand Up @@ -621,7 +623,7 @@ TEST(Statement, bindByNameString)

// Third row with binary buffer and a null parameter
{
const char buffer[] = "binary";
const unsigned char buffer[] = "binary";
insert.bind(amsg, buffer, sizeof(buffer));
insert.bind(aint);
EXPECT_EQ(1, insert.exec());
Expand All @@ -631,7 +633,7 @@ TEST(Statement, bindByNameString)
EXPECT_TRUE(query.hasRow());
EXPECT_FALSE(query.isDone());
EXPECT_EQ(3, query.getColumn(0).getInt64());
EXPECT_STREQ(buffer, query.getColumn(1).getText());
EXPECT_EQ(0, memcmp(buffer, query.getColumn(1).getText(), 6));
EXPECT_TRUE(query.isColumnNull(2));
EXPECT_EQ(0, query.getColumn(2).getInt());
EXPECT_EQ(0.234f, query.getColumn(3).getDouble());
Expand All @@ -657,6 +659,23 @@ TEST(Statement, bindByNameString)
EXPECT_EQ(4294967295U, query.getColumn(2).getUInt());
EXPECT_EQ(12345678900000LL, query.getColumn(4).getInt64());
}

// reset() without clearbindings()
insert.reset();

// Fifth row with string
{
const std::string first = "fir\0st";
insert.bind(amsg, first.c_str(), static_cast<int>(first.size()));
EXPECT_EQ(1, insert.exec());
EXPECT_EQ(SQLITE_DONE, db.getErrorCode());

// Check the result
query.executeStep();
EXPECT_TRUE(query.hasRow());
EXPECT_FALSE(query.isDone());
EXPECT_EQ(first, query.getColumn(1).getString());
}
}

TEST(Statement, bindNoCopyByName)
Expand Down Expand Up @@ -709,9 +728,9 @@ TEST(Statement, bindNoCopyByName)
const std::string ablob = "@blob";
const char* txt1 = "first2";
const std::string txt2 = "sec\0nd2";
const char blob[] = { 'b','l','\0','b','2' };
const unsigned char blob[] = { 'b','l','\0','b','2' };
insert.bindNoCopy(atxt1, txt1);
insert.bindNoCopy(atxt2, txt2);
insert.bindNoCopy(atxt2, txt2.c_str(), static_cast<int>(txt2.size()));
insert.bindNoCopy(ablob, blob, sizeof(blob));
EXPECT_EQ(1, insert.exec());
EXPECT_EQ(2, db.getLastInsertRowid());
Expand All @@ -727,6 +746,28 @@ TEST(Statement, bindNoCopyByName)
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)));
}

insert.reset();
insert.clearBindings();
query.reset();

// Insert a third row with some more variants of bindNoCopy() using std::string names
{
const std::string atxt1 = "@txt1";
const std::string txt1 = "fir\0st";
insert.bindNoCopy(atxt1, txt1);
EXPECT_EQ(1, insert.exec());
EXPECT_EQ(3, db.getLastInsertRowid());
EXPECT_EQ(SQLITE_DONE, db.getErrorCode());

// Check the result
query.executeStep(); // pass on the first row
query.executeStep(); // pass on the second row as well
query.executeStep();
EXPECT_TRUE(query.hasRow());
EXPECT_FALSE(query.isDone());
EXPECT_EQ(txt1, query.getColumn(1).getString());
}
}

TEST(Statement, isColumnNull)
Expand Down