blob: f188a1d4e904355c58970b81f78f3ee6b477e980 [file] [log] [blame]
// 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_forward.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.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();
}
int Statement::StepInternal() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!CheckValid())
return SQLITE_ERROR;
absl::optional<base::ScopedBlockingCall> scoped_blocking_call;
ref_->InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call);
int ret = sqlite3_step(ref_->stmt());
return CheckError(ret);
}
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() == SQLITE_DONE;
}
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() == SQLITE_ROW;
}
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_error_code = sqlite3_bind_null(ref_->stmt(), param_index + 1);
DCHECK_EQ(sqlite_error_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_error_code = sqlite3_bind_int(ref_->stmt(), param_index + 1, val);
DCHECK_EQ(sqlite_error_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_error_code =
sqlite3_bind_int64(ref_->stmt(), param_index + 1, val);
DCHECK_EQ(sqlite_error_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_error_code =
sqlite3_bind_double(ref_->stmt(), param_index + 1, val);
DCHECK_EQ(sqlite_error_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_error_code =
sqlite3_bind_int64(ref_->stmt(), param_index + 1, int_value);
DCHECK_EQ(sqlite_error_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_error_code = sqlite3_bind_text(ref_->stmt(), param_index + 1, val,
-1, SQLITE_TRANSIENT);
DCHECK_EQ(sqlite_error_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_error_code = sqlite3_bind_text(ref_->stmt(), param_index + 1, data,
value.size(), SQLITE_TRANSIENT);
DCHECK_EQ(sqlite_error_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_error_code = sqlite3_bind_blob(ref_->stmt(), param_index + 1, data,
value.size(), SQLITE_TRANSIENT);
DCHECK_EQ(sqlite_error_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::TimeDelta::FromMicroseconds(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));
}
const char* Statement::GetSQLStatement() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return sqlite3_sql(ref_->stmt());
}
int Statement::CheckError(int err) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Please don't add DCHECKs here, OnSqliteError() already has them.
succeeded_ = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE);
if (!succeeded_ && ref_.get() && ref_->database())
return ref_->database()->OnSqliteError(err, this, nullptr);
return err;
}
} // namespace sql