| 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 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
54 ArchiveStatement::~ArchiveStatement() = default;
55
56 bool ArchiveStatement::IsValid() const {
57 return statement_handle_ != nullptr;
58 }
59
60 bool ArchiveStatement::Reset() {
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
89 size_t ArchiveStatement::GetColumnCount() {
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
215 ArchiveStatement::Result ArchiveStatement::Execute() {
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