Add sql::Statement::ColumnStringView method
Analogous to sql::Statement::ColumnBlob returning a base::span, this allows callers to avoid allocating a temporary std::string when the value is immediately passed to a function accepting a string view. For example, this allows sql::Statement::ColumnString16 to be implemented more efficiently. Change-Id: I7538d25aacf14849ddfc75b781b3e82f2d315483 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5854261 Commit-Queue: Andrew Paseltiner <apaseltiner@chromium.org> Reviewed-by: Evan Stade <estade@chromium.org> Cr-Commit-Position: refs/heads/main@{#1354102}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
c36b30a5e6
commit
84724d909b
@ -533,7 +533,7 @@ base::TimeDelta Statement::ColumnTimeDelta(int column_index) {
|
||||
return base::Microseconds(int_value);
|
||||
}
|
||||
|
||||
std::string Statement::ColumnString(int column_index) {
|
||||
std::string_view Statement::ColumnStringView(int column_index) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
@ -542,7 +542,7 @@ std::string Statement::ColumnString(int column_index) {
|
||||
#endif // DCHECK_IS_ON()
|
||||
|
||||
if (!CheckValid())
|
||||
return std::string();
|
||||
return std::string_view();
|
||||
DCHECK_GE(column_index, 0);
|
||||
DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
|
||||
<< "Invalid column index";
|
||||
@ -550,29 +550,18 @@ std::string Statement::ColumnString(int column_index) {
|
||||
const char* string_buffer = reinterpret_cast<const char*>(
|
||||
sqlite3_column_text(ref_->stmt(), column_index));
|
||||
int size = sqlite3_column_bytes(ref_->stmt(), column_index);
|
||||
DCHECK(size == 0 || string_buffer != nullptr)
|
||||
<< "sqlite3_column_text() returned a null buffer for a non-empty string";
|
||||
|
||||
std::string result;
|
||||
if (string_buffer && size > 0)
|
||||
result.assign(string_buffer, size);
|
||||
return result;
|
||||
return std::string_view(string_buffer, base::checked_cast<size_t>(size));
|
||||
}
|
||||
|
||||
std::string Statement::ColumnString(int column_index) {
|
||||
return std::string(ColumnStringView(column_index));
|
||||
}
|
||||
|
||||
std::u16string Statement::ColumnString16(int column_index) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
|
||||
DCHECK(step_called_) << __func__ << " can only be used after Step()";
|
||||
#endif // DCHECK_IS_ON()
|
||||
|
||||
if (!CheckValid())
|
||||
return std::u16string();
|
||||
DCHECK_GE(column_index, 0);
|
||||
DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
|
||||
<< "Invalid column index";
|
||||
|
||||
std::string string = ColumnString(column_index);
|
||||
return string.empty() ? std::u16string() : base::UTF8ToUTF16(string);
|
||||
return base::UTF8ToUTF16(ColumnStringView(column_index));
|
||||
}
|
||||
|
||||
base::span<const uint8_t> Statement::ColumnBlob(int column_index) {
|
||||
|
@ -203,6 +203,19 @@ class COMPONENT_EXPORT(SQL) Statement {
|
||||
// `ColumnBlobAsString16()`.
|
||||
std::u16string ColumnString16(int column_index);
|
||||
|
||||
// Returns a string view pointing to a buffer containing the string data.
|
||||
//
|
||||
// This can be used to avoid allocating a temporary string when the value is
|
||||
// immediately passed to a function accepting a string view. Otherwise, the
|
||||
// string view's contents should be copied to a caller-owned buffer
|
||||
// immediately. Any method call on the `Statement` may invalidate the string
|
||||
// view.
|
||||
//
|
||||
// The string view will be empty (and may have a null data) if the underlying
|
||||
// string is empty. Code that needs to distinguish between empty strings and
|
||||
// NULL should call `GetColumnType()` before calling `ColumnStringView()`.
|
||||
std::string_view ColumnStringView(int column_index);
|
||||
|
||||
// Conforms with base::Time serialization recommendations.
|
||||
//
|
||||
// This is equivalent to the following snippets, which should be replaced.
|
||||
|
@ -320,12 +320,23 @@ TEST_F(StatementTest, BindString) {
|
||||
insert.Reset(/*clear_bound_vars=*/true);
|
||||
}
|
||||
|
||||
Statement select(db_.GetUniqueStatement("SELECT t FROM texts ORDER BY id"));
|
||||
for (const std::string& value : values) {
|
||||
ASSERT_TRUE(select.Step());
|
||||
EXPECT_EQ(value, select.ColumnString(0));
|
||||
{
|
||||
Statement select(db_.GetUniqueStatement("SELECT t FROM texts ORDER BY id"));
|
||||
for (const std::string& value : values) {
|
||||
ASSERT_TRUE(select.Step());
|
||||
EXPECT_EQ(value, select.ColumnString(0));
|
||||
}
|
||||
EXPECT_FALSE(select.Step());
|
||||
}
|
||||
|
||||
{
|
||||
Statement select(db_.GetUniqueStatement("SELECT t FROM texts ORDER BY id"));
|
||||
for (const std::string& value : values) {
|
||||
ASSERT_TRUE(select.Step());
|
||||
EXPECT_EQ(value, select.ColumnStringView(0));
|
||||
}
|
||||
EXPECT_FALSE(select.Step());
|
||||
}
|
||||
EXPECT_FALSE(select.Step());
|
||||
}
|
||||
|
||||
TEST_F(StatementTest, BindString_NullData) {
|
||||
|
Reference in New Issue
Block a user