123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "sql/statement.h"
- #include <stddef.h>
- #include <stdint.h>
- #include "base/containers/span.h"
- #include "base/dcheck_is_on.h"
- #include "base/logging.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/sequence_checker.h"
- #include "base/strings/string_piece.h"
- #include "base/strings/string_util.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/time/time.h"
- #include "sql/sqlite_result_code.h"
- #include "sql/sqlite_result_code_values.h"
- #include "third_party/sqlite/sqlite3.h"
- namespace sql {
- // This empty constructor initializes our reference with an empty one so that
- // we don't have to null-check the ref_ to see if the statement is valid: we
- // only have to check the ref's validity bit.
- Statement::Statement()
- : ref_(base::MakeRefCounted<Database::StatementRef>(nullptr,
- nullptr,
- false)) {}
- Statement::Statement(scoped_refptr<Database::StatementRef> ref)
- : ref_(std::move(ref)) {}
- Statement::~Statement() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // Free the resources associated with this statement. We assume there's only
- // one statement active for a given sqlite3_stmt at any time, so this won't
- // mess with anything.
- Reset(true);
- }
- void Statement::Assign(scoped_refptr<Database::StatementRef> ref) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- Reset(true);
- ref_ = std::move(ref);
- }
- void Statement::Clear() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- Assign(base::MakeRefCounted<Database::StatementRef>(nullptr, nullptr, false));
- succeeded_ = false;
- }
- bool Statement::CheckValid() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // Allow operations to fail silently if a statement was invalidated
- // because the database was closed by an error handler.
- DLOG_IF(FATAL, !ref_->was_valid())
- << "Cannot call mutating statements on an invalid statement.";
- return is_valid();
- }
- SqliteResultCode Statement::StepInternal() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!CheckValid())
- return SqliteResultCode::kError;
- absl::optional<base::ScopedBlockingCall> scoped_blocking_call;
- ref_->InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call);
- auto sqlite_result_code = ToSqliteResultCode(sqlite3_step(ref_->stmt()));
- return CheckSqliteResultCode(sqlite_result_code);
- }
- bool Statement::Run() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- #if DCHECK_IS_ON()
- DCHECK(!run_called_) << "Run() must be called exactly once";
- run_called_ = true;
- DCHECK(!step_called_) << "Run() must not be mixed with Step()";
- #endif // DCHECK_IS_ON()
- return StepInternal() == SqliteResultCode::kDone;
- }
- bool Statement::Step() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- #if DCHECK_IS_ON()
- DCHECK(!run_called_) << "Run() must not be mixed with Step()";
- step_called_ = true;
- #endif // DCHECK_IS_ON()
- return StepInternal() == SqliteResultCode::kRow;
- }
- void Statement::Reset(bool clear_bound_vars) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- absl::optional<base::ScopedBlockingCall> scoped_blocking_call;
- ref_->InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call);
- if (is_valid()) {
- if (clear_bound_vars)
- sqlite3_clear_bindings(ref_->stmt());
- // StepInternal() cannot track success because statements may be reset
- // before reaching SQLITE_DONE. Don't call CheckError() because
- // sqlite3_reset() returns the last step error, which StepInternal() already
- // checked.
- sqlite3_reset(ref_->stmt());
- }
- // Potentially release dirty cache pages if an autocommit statement made
- // changes.
- if (ref_->database())
- ref_->database()->ReleaseCacheMemoryIfNeeded(false);
- succeeded_ = false;
- #if DCHECK_IS_ON()
- run_called_ = false;
- step_called_ = false;
- #endif // DCHECK_IS_ON()
- }
- bool Statement::Succeeded() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return is_valid() && succeeded_;
- }
- void Statement::BindNull(int param_index) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- #if DCHECK_IS_ON()
- DCHECK(!run_called_) << __func__ << " must not be called after Run()";
- DCHECK(!step_called_) << __func__ << " must not be called after Step()";
- #endif // DCHECK_IS_ON()
- if (!is_valid())
- return;
- DCHECK_GE(param_index, 0);
- DCHECK_LT(param_index, sqlite3_bind_parameter_count(ref_->stmt()))
- << "Invalid parameter index";
- int sqlite_result_code = sqlite3_bind_null(ref_->stmt(), param_index + 1);
- DCHECK_EQ(sqlite_result_code, SQLITE_OK);
- }
- void Statement::BindBool(int param_index, bool val) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return BindInt64(param_index, val ? 1 : 0);
- }
- void Statement::BindInt(int param_index, int val) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- #if DCHECK_IS_ON()
- DCHECK(!run_called_) << __func__ << " must not be called after Run()";
- DCHECK(!step_called_) << __func__ << " must not be called after Step()";
- #endif // DCHECK_IS_ON()
- if (!is_valid())
- return;
- DCHECK_GE(param_index, 0);
- DCHECK_LT(param_index, sqlite3_bind_parameter_count(ref_->stmt()))
- << "Invalid parameter index";
- int sqlite_result_code = sqlite3_bind_int(ref_->stmt(), param_index + 1, val);
- DCHECK_EQ(sqlite_result_code, SQLITE_OK);
- }
- void Statement::BindInt64(int param_index, int64_t val) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- #if DCHECK_IS_ON()
- DCHECK(!run_called_) << __func__ << " must not be called after Run()";
- DCHECK(!step_called_) << __func__ << " must not be called after Step()";
- #endif // DCHECK_IS_ON()
- if (!is_valid())
- return;
- DCHECK_GE(param_index, 0);
- DCHECK_LT(param_index, sqlite3_bind_parameter_count(ref_->stmt()))
- << "Invalid parameter index";
- int sqlite_result_code =
- sqlite3_bind_int64(ref_->stmt(), param_index + 1, val);
- DCHECK_EQ(sqlite_result_code, SQLITE_OK);
- }
- void Statement::BindDouble(int param_index, double val) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- #if DCHECK_IS_ON()
- DCHECK(!run_called_) << __func__ << " must not be called after Run()";
- DCHECK(!step_called_) << __func__ << " must not be called after Step()";
- #endif // DCHECK_IS_ON()
- if (!is_valid())
- return;
- DCHECK_GE(param_index, 0);
- DCHECK_LT(param_index, sqlite3_bind_parameter_count(ref_->stmt()))
- << "Invalid parameter index";
- int sqlite_result_code =
- sqlite3_bind_double(ref_->stmt(), param_index + 1, val);
- DCHECK_EQ(sqlite_result_code, SQLITE_OK);
- }
- void Statement::BindTime(int param_index, base::Time val) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- #if DCHECK_IS_ON()
- DCHECK(!run_called_) << __func__ << " must not be called after Run()";
- DCHECK(!step_called_) << __func__ << " must not be called after Step()";
- #endif // DCHECK_IS_ON()
- if (!is_valid())
- return;
- DCHECK_GE(param_index, 0);
- DCHECK_LT(param_index, sqlite3_bind_parameter_count(ref_->stmt()))
- << "Invalid parameter index";
- int64_t int_value = val.ToDeltaSinceWindowsEpoch().InMicroseconds();
- int sqlite_result_code =
- sqlite3_bind_int64(ref_->stmt(), param_index + 1, int_value);
- DCHECK_EQ(sqlite_result_code, SQLITE_OK);
- }
- void Statement::BindCString(int param_index, const char* val) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- #if DCHECK_IS_ON()
- DCHECK(!run_called_) << __func__ << " must not be called after Run()";
- DCHECK(!step_called_) << __func__ << " must not be called after Step()";
- #endif // DCHECK_IS_ON()
- DCHECK(val);
- if (!is_valid())
- return;
- DCHECK_GE(param_index, 0);
- DCHECK_LT(param_index, sqlite3_bind_parameter_count(ref_->stmt()))
- << "Invalid parameter index";
- // If the string length is more than SQLITE_MAX_LENGTH (or the per-database
- // SQLITE_LIMIT_LENGTH limit), sqlite3_bind_text() fails with SQLITE_TOOBIG.
- //
- // We're not currently handling this error. SQLITE_MAX_LENGTH is set to the
- // default (1 billion bytes) in Chrome's SQLite build, so this is an unlilely
- // issue.
- int sqlite_result_code = sqlite3_bind_text(ref_->stmt(), param_index + 1, val,
- -1, SQLITE_TRANSIENT);
- DCHECK_EQ(sqlite_result_code, SQLITE_OK);
- }
- void Statement::BindString(int param_index, base::StringPiece value) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- #if DCHECK_IS_ON()
- DCHECK(!run_called_) << __func__ << " must not be called after Run()";
- DCHECK(!step_called_) << __func__ << " must not be called after Step()";
- #endif // DCHECK_IS_ON()
- if (!is_valid())
- return;
- DCHECK_GE(param_index, 0);
- DCHECK_LT(param_index, sqlite3_bind_parameter_count(ref_->stmt()))
- << "Invalid parameter index";
- // base::StringPiece::data() may return null for empty pieces. In particular,
- // this may happen when the StringPiece is created from the default
- // constructor.
- //
- // However, sqlite3_bind_text() always interprets a nullptr data argument as a
- // NULL value, instead of an empty BLOB value.
- static constexpr char kEmptyPlaceholder[] = {0x00};
- const char* data = (value.size() > 0) ? value.data() : kEmptyPlaceholder;
- // If the string length is more than SQLITE_MAX_LENGTH (or the per-database
- // SQLITE_LIMIT_LENGTH limit), sqlite3_bind_text() fails with SQLITE_TOOBIG.
- //
- // We're not currently handling this error. SQLITE_MAX_LENGTH is set to the
- // default (1 billion bytes) in Chrome's SQLite build, so this is an unlilely
- // issue.
- int sqlite_result_code = sqlite3_bind_text(
- ref_->stmt(), param_index + 1, data, value.size(), SQLITE_TRANSIENT);
- DCHECK_EQ(sqlite_result_code, SQLITE_OK);
- }
- void Statement::BindString16(int param_index, base::StringPiece16 value) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return BindString(param_index, base::UTF16ToUTF8(value));
- }
- void Statement::BindBlob(int param_index, base::span<const uint8_t> value) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- #if DCHECK_IS_ON()
- DCHECK(!run_called_) << __func__ << " must not be called after Run()";
- DCHECK(!step_called_) << __func__ << " must not be called after Step()";
- #endif // DCHECK_IS_ON()
- if (!is_valid())
- return;
- DCHECK_GE(param_index, 0);
- DCHECK_LT(param_index, sqlite3_bind_parameter_count(ref_->stmt()))
- << "Invalid parameter index";
- // span::data() may return null for empty spans. In particular, this may
- // happen when the span is created out of a std::vector, because
- // std::vector::data() may (or may not) return null for empty vectors.
- //
- // However, sqlite3_bind_blob() always interprets a nullptr data argument as a
- // NULL value, instead of an empty BLOB value.
- //
- // While the difference between NULL and an empty BLOB may not matter in some
- // cases, it may also cause subtle bugs in other cases. So, we cannot pass
- // span.data() directly to sqlite3_bind_blob().
- static constexpr uint8_t kEmptyPlaceholder[] = {0x00};
- const uint8_t* data = (value.size() > 0) ? value.data() : kEmptyPlaceholder;
- // If the string length is more than SQLITE_MAX_LENGTH (or the per-database
- // SQLITE_LIMIT_LENGTH limit), sqlite3_bind_text() fails with SQLITE_TOOBIG.
- //
- // We're not currently handling this error. SQLITE_MAX_LENGTH is set to the
- // default (1 billion bytes) in Chrome's SQLite build, so this is an unlilely
- // issue.
- int sqlite_result_code = sqlite3_bind_blob(
- ref_->stmt(), param_index + 1, data, value.size(), SQLITE_TRANSIENT);
- DCHECK_EQ(sqlite_result_code, SQLITE_OK);
- }
- int Statement::ColumnCount() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!is_valid())
- return 0;
- return sqlite3_column_count(ref_->stmt());
- }
- // Verify that our enum matches sqlite's values.
- static_assert(static_cast<int>(ColumnType::kInteger) == SQLITE_INTEGER,
- "INTEGER mismatch");
- static_assert(static_cast<int>(ColumnType::kFloat) == SQLITE_FLOAT,
- "FLOAT mismatch");
- static_assert(static_cast<int>(ColumnType::kText) == SQLITE_TEXT,
- "TEXT mismatch");
- static_assert(static_cast<int>(ColumnType::kBlob) == SQLITE_BLOB,
- "BLOB mismatch");
- static_assert(static_cast<int>(ColumnType::kNull) == SQLITE_NULL,
- "NULL mismatch");
- ColumnType Statement::GetColumnType(int col) {
- 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()
- return static_cast<enum ColumnType>(sqlite3_column_type(ref_->stmt(), col));
- }
- bool Statement::ColumnBool(int column_index) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return static_cast<bool>(ColumnInt64(column_index));
- }
- int Statement::ColumnInt(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 0;
- DCHECK_GE(column_index, 0);
- DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
- << "Invalid column index";
- return sqlite3_column_int(ref_->stmt(), column_index);
- }
- int64_t Statement::ColumnInt64(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 0;
- DCHECK_GE(column_index, 0);
- DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
- << "Invalid column index";
- return sqlite3_column_int64(ref_->stmt(), column_index);
- }
- double Statement::ColumnDouble(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 0;
- DCHECK_GE(column_index, 0);
- DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
- << "Invalid column index";
- return sqlite3_column_double(ref_->stmt(), column_index);
- }
- base::Time Statement::ColumnTime(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 base::Time();
- DCHECK_GE(column_index, 0);
- DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
- << "Invalid column index";
- int64_t int_value = sqlite3_column_int64(ref_->stmt(), column_index);
- return base::Time::FromDeltaSinceWindowsEpoch(base::Microseconds(int_value));
- }
- std::string Statement::ColumnString(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::string();
- DCHECK_GE(column_index, 0);
- DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
- << "Invalid 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);
- std::string result;
- if (string_buffer && size > 0)
- result.assign(string_buffer, size);
- return result;
- }
- 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);
- }
- base::span<const uint8_t> Statement::ColumnBlob(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 base::span<const uint8_t>();
- DCHECK_GE(column_index, 0);
- DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
- << "Invalid column index";
- int result_size = sqlite3_column_bytes(ref_->stmt(), column_index);
- const void* result_buffer = sqlite3_column_blob(ref_->stmt(), column_index);
- DCHECK(result_size == 0 || result_buffer != nullptr)
- << "sqlite3_column_blob() returned a null buffer for a non-empty BLOB";
- return base::make_span(static_cast<const uint8_t*>(result_buffer),
- result_size);
- }
- bool Statement::ColumnBlobAsString(int column_index, std::string* result) {
- 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 false;
- DCHECK_GE(column_index, 0);
- DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
- << "Invalid column index";
- const void* result_buffer = sqlite3_column_blob(ref_->stmt(), column_index);
- int size = sqlite3_column_bytes(ref_->stmt(), column_index);
- if (result_buffer && size > 0) {
- result->assign(reinterpret_cast<const char*>(result_buffer), size);
- } else {
- result->clear();
- }
- return true;
- }
- bool Statement::ColumnBlobAsVector(int column_index,
- std::vector<char>* result) {
- 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 false;
- DCHECK_GE(column_index, 0);
- DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
- << "Invalid column index";
- const void* result_buffer = sqlite3_column_blob(ref_->stmt(), column_index);
- int size = sqlite3_column_bytes(ref_->stmt(), column_index);
- if (result_buffer && size > 0) {
- // Unlike std::string, std::vector does not have an assign() overload that
- // takes a buffer and a size.
- result->assign(static_cast<const char*>(result_buffer),
- static_cast<const char*>(result_buffer) + size);
- } else {
- result->clear();
- }
- return true;
- }
- bool Statement::ColumnBlobAsVector(int column_index,
- std::vector<uint8_t>* result) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return ColumnBlobAsVector(column_index,
- reinterpret_cast<std::vector<char>*>(result));
- }
- std::string Statement::GetSQLStatement() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // SQLite promises to keep the returned buffer alive until the statement is
- // finalized. We immediately copy the buffer contents into a std::string so we
- // don't need to worry about its lifetime. The performance overhead is
- // acceptable because this method should only be invoked for logging details
- // about SQLite errors.
- //
- // We use sqlite3_sql() instead of sqlite3_expanded_sql() because:
- // - The returned SQL string matches the source code, making it easy to
- // search.
- // - This works with SQL statements that work with large data, such as BLOBS
- // storing images.
- // - The returned string is free of bound values, so it does not contain any
- // PII that would raise privacy concerns around logging.
- //
- // Do not change this to use sqlite3_expanded_sql(). If that need ever arises
- // in the future, make a new function instead listing the above caveats.
- //
- // See https://www.sqlite.org/c3ref/expanded_sql.html for more details on the
- // difference between sqlite3_sql() and sqlite3_expanded_sql().
- return sqlite3_sql(ref_->stmt());
- }
- SqliteResultCode Statement::CheckSqliteResultCode(
- SqliteResultCode sqlite_result_code) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- succeeded_ = IsSqliteSuccessCode(sqlite_result_code);
- if (!succeeded_ && ref_.get() && ref_->database()) {
- auto sqlite_error_code = ToSqliteErrorCode(sqlite_result_code);
- ref_->database()->OnSqliteError(sqlite_error_code, this, nullptr);
- }
- return sqlite_result_code;
- }
- } // namespace sql
|