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  Handle(const Handle&) = delete;
45 
46  Handle& operator=(const Handle&) = delete;
47 };
48 
49 ArchiveStatement::ArchiveStatement(void* db, const std::string& statememt)
50  : statement_handle_(std::make_unique<Handle>(db, statememt)) {
51  if (!statement_handle_->IsValid()) {
52  statement_handle_.reset();
53  }
54 }
55 
57 
59  return statement_handle_ != nullptr;
60 }
61 
63  if (!IsValid()) {
64  return false;
65  }
66  if (::sqlite3_reset(statement_handle_->Get()) != SQLITE_OK) {
67  return false;
68  }
69 
70  if (::sqlite3_clear_bindings(statement_handle_->Get()) != SQLITE_OK) {
71  return false;
72  }
73 
74  return true;
75 }
76 
77 static constexpr int ToParam(size_t index) {
78  /*
79  * sqlite parameters begin from 1
80  */
81  return static_cast<int>(index + 1);
82 }
83 
84 static constexpr int ToColumn(size_t index) {
85  /*
86  * sqlite columns begin from 0
87  */
88  return static_cast<int>(index);
89 }
90 
92  if (!IsValid()) {
93  return 0u;
94  }
95  return ::sqlite3_column_count(statement_handle_->Get());
96 }
97 
98 /*
99  * Bind Variants
100  */
101 bool ArchiveStatement::WriteValue(size_t index, const std::string& item) {
102  if (!IsValid()) {
103  return false;
104  }
105  return ::sqlite3_bind_text(statement_handle_->Get(), //
106  ToParam(index), //
107  item.data(), //
108  static_cast<int>(item.size()), //
109  SQLITE_TRANSIENT) == SQLITE_OK;
110 }
111 
112 bool ArchiveStatement::BindIntegral(size_t index, int64_t item) {
113  if (!IsValid()) {
114  return false;
115  }
116  return ::sqlite3_bind_int64(statement_handle_->Get(), //
117  ToParam(index), //
118  item) == SQLITE_OK;
119 }
120 
121 bool ArchiveStatement::WriteValue(size_t index, double item) {
122  if (!IsValid()) {
123  return false;
124  }
125  return ::sqlite3_bind_double(statement_handle_->Get(), //
126  ToParam(index), //
127  item) == SQLITE_OK;
128 }
129 
130 bool ArchiveStatement::WriteValue(size_t index, const Allocation& item) {
131  if (!IsValid()) {
132  return false;
133  }
134  return ::sqlite3_bind_blob(statement_handle_->Get(), //
135  ToParam(index), //
136  item.GetBuffer(), //
137  static_cast<int>(item.GetLength()), //
138  SQLITE_TRANSIENT) == SQLITE_OK;
139 }
140 
141 /*
142  * Column Variants
143  */
144 bool ArchiveStatement::ColumnIntegral(size_t index, int64_t& item) {
145  if (!IsValid()) {
146  return false;
147  }
148  item = ::sqlite3_column_int64(statement_handle_->Get(), ToColumn(index));
149  return true;
150 }
151 
152 bool ArchiveStatement::ReadValue(size_t index, double& item) {
153  if (!IsValid()) {
154  return false;
155  }
156  item = ::sqlite3_column_double(statement_handle_->Get(), ToColumn(index));
157  return true;
158 }
159 
160 /*
161  * For cases where byte sizes of column data is necessary, the
162  * recommendations in https://www.sqlite.org/c3ref/column_blob.html regarding
163  * type conversions are followed.
164  *
165  * TL;DR: Access blobs then bytes.
166  */
167 
168 bool ArchiveStatement::ReadValue(size_t index, std::string& item) {
169  if (!IsValid()) {
170  return false;
171  }
172  /*
173  * Get the character data
174  */
175  auto chars = reinterpret_cast<const char*>(
176  ::sqlite3_column_text(statement_handle_->Get(), ToColumn(index)));
177 
178  /*
179  * Get the length of the string (in bytes)
180  */
181  size_t textByteSize =
182  ::sqlite3_column_bytes(statement_handle_->Get(), ToColumn(index));
183 
184  std::string text(chars, textByteSize);
185  item.swap(text);
186 
187  return true;
188 }
189 
190 bool ArchiveStatement::ReadValue(size_t index, Allocation& item) {
191  if (!IsValid()) {
192  return false;
193  }
194  /*
195  * Get a blob pointer
196  */
197  auto blob = reinterpret_cast<const uint8_t*>(
198  ::sqlite3_column_blob(statement_handle_->Get(), ToColumn(index)));
199 
200  /*
201  * Decode the number of bytes in the blob
202  */
203  size_t byteSize =
204  ::sqlite3_column_bytes(statement_handle_->Get(), ToColumn(index));
205 
206  /*
207  * Reszie the host allocation and move the blob contents into it
208  */
209  if (!item.Truncate(byteSize, false /* npot */)) {
210  return false;
211  }
212 
213  memmove(item.GetBuffer(), blob, byteSize);
214  return true;
215 }
216 
218  if (!IsValid()) {
219  return Result::kFailure;
220  }
221  switch (::sqlite3_step(statement_handle_->Get())) {
222  case SQLITE_DONE:
223  return Result::kDone;
224  case SQLITE_ROW:
225  return Result::kRow;
226  default:
227  return Result::kFailure;
228  }
229 }
230 
231 } // 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:62
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:24
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:217
impeller::ToColumn
static constexpr int ToColumn(size_t index)
Definition: archive_statement.cc:84
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:101
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:20
impeller::Allocation
Definition: allocation.h:16
impeller::ToParam
static constexpr int ToParam(size_t index)
Definition: archive_statement.cc:77
impeller::ArchiveStatement::Result::kFailure
@ kFailure
impeller::ArchiveStatement::GetColumnCount
size_t GetColumnCount()
Definition: archive_statement.cc:91
std
Definition: comparable.h:95
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:32
impeller::ArchiveStatement::IsValid
bool IsValid() const
Definition: archive_statement.cc:58