blob: d6f6f5722fc5a936aea7f8a1c29a0b07476416bc [file] [log] [blame]
// Copyright 2013 The Flutter 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 "impeller/archivist/archive_statement.h"
#include <string>
#include "flutter/fml/logging.h"
#include "third_party/sqlite/sqlite3.h"
namespace impeller {
struct ArchiveStatement::Handle {
Handle(void* db, const std::string& statememt) {
if (db == nullptr) {
return;
}
::sqlite3_stmt* handle = nullptr;
if (::sqlite3_prepare_v2(reinterpret_cast<sqlite3*>(db), //
statememt.c_str(), //
static_cast<int>(statememt.size()), //
&handle, //
nullptr) == SQLITE_OK) {
handle_ = handle;
}
}
~Handle() {
if (handle_ == nullptr) {
return;
}
auto res = ::sqlite3_finalize(handle_);
FML_CHECK(res == SQLITE_OK) << "Unable to finalize the archive.";
}
bool IsValid() const { return handle_ != nullptr; }
::sqlite3_stmt* Get() const { return handle_; }
private:
::sqlite3_stmt* handle_ = nullptr;
FML_DISALLOW_COPY_AND_ASSIGN(Handle);
};
ArchiveStatement::ArchiveStatement(void* db, const std::string& statememt)
: statement_handle_(std::make_unique<Handle>(db, statememt)) {
if (!statement_handle_->IsValid()) {
statement_handle_.reset();
}
}
ArchiveStatement::~ArchiveStatement() = default;
bool ArchiveStatement::IsValid() const {
return statement_handle_ != nullptr;
}
bool ArchiveStatement::Reset() {
if (!IsValid()) {
return false;
}
if (::sqlite3_reset(statement_handle_->Get()) != SQLITE_OK) {
return false;
}
if (::sqlite3_clear_bindings(statement_handle_->Get()) != SQLITE_OK) {
return false;
}
return true;
}
static constexpr int ToParam(size_t index) {
/*
* sqlite parameters begin from 1
*/
return static_cast<int>(index + 1);
}
static constexpr int ToColumn(size_t index) {
/*
* sqlite columns begin from 0
*/
return static_cast<int>(index);
}
size_t ArchiveStatement::GetColumnCount() {
if (!IsValid()) {
return 0u;
}
return ::sqlite3_column_count(statement_handle_->Get());
}
/*
* Bind Variants
*/
bool ArchiveStatement::WriteValue(size_t index, const std::string& item) {
if (!IsValid()) {
return false;
}
return ::sqlite3_bind_text(statement_handle_->Get(), //
ToParam(index), //
item.data(), //
static_cast<int>(item.size()), //
SQLITE_TRANSIENT) == SQLITE_OK;
}
bool ArchiveStatement::BindIntegral(size_t index, int64_t item) {
if (!IsValid()) {
return false;
}
return ::sqlite3_bind_int64(statement_handle_->Get(), //
ToParam(index), //
item) == SQLITE_OK;
}
bool ArchiveStatement::WriteValue(size_t index, double item) {
if (!IsValid()) {
return false;
}
return ::sqlite3_bind_double(statement_handle_->Get(), //
ToParam(index), //
item) == SQLITE_OK;
}
bool ArchiveStatement::WriteValue(size_t index, const Allocation& item) {
if (!IsValid()) {
return false;
}
return ::sqlite3_bind_blob(statement_handle_->Get(), //
ToParam(index), //
item.GetBuffer(), //
static_cast<int>(item.GetLength()), //
SQLITE_TRANSIENT) == SQLITE_OK;
}
/*
* Column Variants
*/
bool ArchiveStatement::ColumnIntegral(size_t index, int64_t& item) {
if (!IsValid()) {
return false;
}
item = ::sqlite3_column_int64(statement_handle_->Get(), ToColumn(index));
return true;
}
bool ArchiveStatement::ReadValue(size_t index, double& item) {
if (!IsValid()) {
return false;
}
item = ::sqlite3_column_double(statement_handle_->Get(), ToColumn(index));
return true;
}
/*
* For cases where byte sizes of column data is necessary, the
* recommendations in https://www.sqlite.org/c3ref/column_blob.html regarding
* type conversions are followed.
*
* TL;DR: Access blobs then bytes.
*/
bool ArchiveStatement::ReadValue(size_t index, std::string& item) {
if (!IsValid()) {
return false;
}
/*
* Get the character data
*/
auto chars = reinterpret_cast<const char*>(
::sqlite3_column_text(statement_handle_->Get(), ToColumn(index)));
/*
* Get the length of the string (in bytes)
*/
size_t textByteSize =
::sqlite3_column_bytes(statement_handle_->Get(), ToColumn(index));
std::string text(chars, textByteSize);
item.swap(text);
return true;
}
bool ArchiveStatement::ReadValue(size_t index, Allocation& item) {
if (!IsValid()) {
return false;
}
/*
* Get a blob pointer
*/
auto blob = reinterpret_cast<const uint8_t*>(
::sqlite3_column_blob(statement_handle_->Get(), ToColumn(index)));
/*
* Decode the number of bytes in the blob
*/
size_t byteSize =
::sqlite3_column_bytes(statement_handle_->Get(), ToColumn(index));
/*
* Reszie the host allocation and move the blob contents into it
*/
if (!item.Truncate(byteSize, false /* npot */)) {
return false;
}
memmove(item.GetBuffer(), blob, byteSize);
return true;
}
ArchiveStatement::Result ArchiveStatement::Execute() {
if (!IsValid()) {
return Result::kFailure;
}
switch (::sqlite3_step(statement_handle_->Get())) {
case SQLITE_DONE:
return Result::kDone;
case SQLITE_ROW:
return Result::kRow;
default:
return Result::kFailure;
}
}
} // namespace impeller