| 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
5 #include "impeller/archivist/archive_statement.h"
6
7 #include <string>
8
9 #include "flutter/fml/logging.h"
10 #include "third_party/sqlite/sqlite3.h"
11
12 namespace impeller {
13
14 struct ArchiveStatement::Handle {
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
56 ArchiveStatement::~ArchiveStatement() = default;
57
58 bool ArchiveStatement::IsValid() const {
59 return statement_handle_ != nullptr;
60 }
61
62 bool ArchiveStatement::Reset() {
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
91 size_t ArchiveStatement::GetColumnCount() {
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
217 ArchiveStatement::Result ArchiveStatement::Execute() {
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