Flutter Impeller
archive_statement.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <string>
8 
9 #include "flutter/fml/logging.h"
10 #include "third_party/sqlite/sqlite3.h"
11 
12 namespace impeller {
13 
15  Handle(void* db, const std::string& statememt) {
16  if (db == nullptr) {
17  return;
18  }
19  ::sqlite3_stmt* handle = nullptr;
20  if (::sqlite3_prepare_v2(reinterpret_cast<sqlite3*>(db), //
21  statememt.c_str(), //
22  static_cast<int>(statememt.size()), //
23  &handle, //
24  nullptr) == SQLITE_OK) {
25  handle_ = handle;
26  }
27  }
28 
29  ~Handle() {
30  if (handle_ == nullptr) {
31  return;
32  }
33  auto res = ::sqlite3_finalize(handle_);
34  FML_CHECK(res == SQLITE_OK) << "Unable to finalize the archive.";
35  }
36 
37  bool IsValid() const { return handle_ != nullptr; }
38 
39  ::sqlite3_stmt* Get() const { return handle_; }
40 
41  private:
42  ::sqlite3_stmt* handle_ = nullptr;
43 
44  FML_DISALLOW_COPY_AND_ASSIGN(Handle);
45 };
46 
47 ArchiveStatement::ArchiveStatement(void* db, const std::string& statememt)
48  : statement_handle_(std::make_unique<Handle>(db, statememt)) {
49  if (!statement_handle_->IsValid()) {
50  statement_handle_.reset();
51  }
52 }
53 
55 
57  return statement_handle_ != nullptr;
58 }
59 
61  if (!IsValid()) {
62  return false;
63  }
64  if (::sqlite3_reset(statement_handle_->Get()) != SQLITE_OK) {
65  return false;
66  }
67 
68  if (::sqlite3_clear_bindings(statement_handle_->Get()) != SQLITE_OK) {
69  return false;
70  }
71 
72  return true;
73 }
74 
75 static constexpr int ToParam(size_t index) {
76  /*
77  * sqlite parameters begin from 1
78  */
79  return static_cast<int>(index + 1);
80 }
81 
82 static constexpr int ToColumn(size_t index) {
83  /*
84  * sqlite columns begin from 0
85  */
86  return static_cast<int>(index);
87 }
88 
90  if (!IsValid()) {
91  return 0u;
92  }
93  return ::sqlite3_column_count(statement_handle_->Get());
94 }
95 
96 /*
97  * Bind Variants
98  */
99 bool ArchiveStatement::WriteValue(size_t index, const std::string& item) {
100  if (!IsValid()) {
101  return false;
102  }
103  return ::sqlite3_bind_text(statement_handle_->Get(), //
104  ToParam(index), //
105  item.data(), //
106  static_cast<int>(item.size()), //
107  SQLITE_TRANSIENT) == SQLITE_OK;
108 }
109 
110 bool ArchiveStatement::BindIntegral(size_t index, int64_t item) {
111  if (!IsValid()) {
112  return false;
113  }
114  return ::sqlite3_bind_int64(statement_handle_->Get(), //
115  ToParam(index), //
116  item) == SQLITE_OK;
117 }
118 
119 bool ArchiveStatement::WriteValue(size_t index, double item) {
120  if (!IsValid()) {
121  return false;
122  }
123  return ::sqlite3_bind_double(statement_handle_->Get(), //
124  ToParam(index), //
125  item) == SQLITE_OK;
126 }
127 
128 bool ArchiveStatement::WriteValue(size_t index, const Allocation& item) {
129  if (!IsValid()) {
130  return false;
131  }
132  return ::sqlite3_bind_blob(statement_handle_->Get(), //
133  ToParam(index), //
134  item.GetBuffer(), //
135  static_cast<int>(item.GetLength()), //
136  SQLITE_TRANSIENT) == SQLITE_OK;
137 }
138 
139 /*
140  * Column Variants
141  */
142 bool ArchiveStatement::ColumnIntegral(size_t index, int64_t& item) {
143  if (!IsValid()) {
144  return false;
145  }
146  item = ::sqlite3_column_int64(statement_handle_->Get(), ToColumn(index));
147  return true;
148 }
149 
150 bool ArchiveStatement::ReadValue(size_t index, double& item) {
151  if (!IsValid()) {
152  return false;
153  }
154  item = ::sqlite3_column_double(statement_handle_->Get(), ToColumn(index));
155  return true;
156 }
157 
158 /*
159  * For cases where byte sizes of column data is necessary, the
160  * recommendations in https://www.sqlite.org/c3ref/column_blob.html regarding
161  * type conversions are followed.
162  *
163  * TL;DR: Access blobs then bytes.
164  */
165 
166 bool ArchiveStatement::ReadValue(size_t index, std::string& item) {
167  if (!IsValid()) {
168  return false;
169  }
170  /*
171  * Get the character data
172  */
173  auto chars = reinterpret_cast<const char*>(
174  ::sqlite3_column_text(statement_handle_->Get(), ToColumn(index)));
175 
176  /*
177  * Get the length of the string (in bytes)
178  */
179  size_t textByteSize =
180  ::sqlite3_column_bytes(statement_handle_->Get(), ToColumn(index));
181 
182  std::string text(chars, textByteSize);
183  item.swap(text);
184 
185  return true;
186 }
187 
188 bool ArchiveStatement::ReadValue(size_t index, Allocation& item) {
189  if (!IsValid()) {
190  return false;
191  }
192  /*
193  * Get a blob pointer
194  */
195  auto blob = reinterpret_cast<const uint8_t*>(
196  ::sqlite3_column_blob(statement_handle_->Get(), ToColumn(index)));
197 
198  /*
199  * Decode the number of bytes in the blob
200  */
201  size_t byteSize =
202  ::sqlite3_column_bytes(statement_handle_->Get(), ToColumn(index));
203 
204  /*
205  * Reszie the host allocation and move the blob contents into it
206  */
207  if (!item.Truncate(byteSize, false /* npot */)) {
208  return false;
209  }
210 
211  memmove(item.GetBuffer(), blob, byteSize);
212  return true;
213 }
214 
216  if (!IsValid()) {
217  return Result::kFailure;
218  }
219  switch (::sqlite3_step(statement_handle_->Get())) {
220  case SQLITE_DONE:
221  return Result::kDone;
222  case SQLITE_ROW:
223  return Result::kRow;
224  default:
225  return Result::kFailure;
226  }
227 }
228 
229 } // namespace impeller
impeller::ArchiveStatement::Reset
bool Reset()
All writes after the last successfull Run call are reset. Since statements are expensive to create,...
Definition: archive_statement.cc:60
impeller::ArchiveStatement::Result
Result
Definition: archive_statement.h:26
impeller::ArchiveStatement::Handle::~Handle
~Handle()
Definition: archive_statement.cc:29
impeller::Allocation::GetLength
size_t GetLength() const
Definition: allocation.cc:25
impeller::ArchiveStatement::Result::kDone
@ kDone
impeller::ArchiveStatement::Handle::Handle
Handle(void *db, const std::string &statememt)
Definition: archive_statement.cc:15
impeller::ArchiveStatement::Execute
Result Execute()
Execute the given statement with the provided data.
Definition: archive_statement.cc:215
impeller::ToColumn
static constexpr int ToColumn(size_t index)
Definition: archive_statement.cc:82
impeller::ArchiveStatement::Handle::Get
::sqlite3_stmt * Get() const
Definition: archive_statement.cc:39
archive_statement.h
impeller::ArchiveStatement::WriteValue
bool WriteValue(size_t index, const std::string &item)
Definition: archive_statement.cc:99
impeller::ArchiveStatement::ReadValue
bool ReadValue(size_t index, T &item)
Definition: archive_statement.h:69
impeller::ArchiveStatement::Handle::IsValid
bool IsValid() const
Definition: archive_statement.cc:37
impeller::Allocation::GetBuffer
uint8_t * GetBuffer() const
Definition: allocation.cc:21
impeller::Allocation
Definition: allocation.h:15
impeller::ToParam
static constexpr int ToParam(size_t index)
Definition: archive_statement.cc:75
impeller::ArchiveStatement::Result::kFailure
@ kFailure
impeller::ArchiveStatement::GetColumnCount
size_t GetColumnCount()
Definition: archive_statement.cc:89
std
Definition: comparable.h:98
impeller::ArchiveStatement::Result::kRow
@ kRow
impeller::ArchiveStatement::~ArchiveStatement
~ArchiveStatement()
impeller::ArchiveStatement::Handle
Definition: archive_statement.cc:14
impeller
Definition: aiks_context.cc:10
impeller::Allocation::Truncate
bool Truncate(size_t length, bool npot=true)
Definition: allocation.cc:33
impeller::ArchiveStatement::IsValid
bool IsValid() const
Definition: archive_statement.cc:56