// 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 #include #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(nullptr, nullptr, false)) {} Statement::Statement(scoped_refptr 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 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(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 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 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 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(ColumnType::kInteger) == SQLITE_INTEGER, "INTEGER mismatch"); static_assert(static_cast(ColumnType::kFloat) == SQLITE_FLOAT, "FLOAT mismatch"); static_assert(static_cast(ColumnType::kText) == SQLITE_TEXT, "TEXT mismatch"); static_assert(static_cast(ColumnType::kBlob) == SQLITE_BLOB, "BLOB mismatch"); static_assert(static_cast(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(sqlite3_column_type(ref_->stmt(), col)); } bool Statement::ColumnBool(int column_index) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return static_cast(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( 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 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(); 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(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(result_buffer), size); } else { result->clear(); } return true; } bool Statement::ColumnBlobAsVector(int column_index, std::vector* 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(result_buffer), static_cast(result_buffer) + size); } else { result->clear(); } return true; } bool Statement::ColumnBlobAsVector(int column_index, std::vector* result) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return ColumnBlobAsVector(column_index, reinterpret_cast*>(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