1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define LOG_TAG "ExtensionCloudCursorImpl"
17 #include "cloud_cursor_impl.h"
18 #include <set>
19 #include "extension_util.h"
20 #include "log_print.h"
21
22 namespace OHOS::CloudData {
23 static std::map<std::string, std::string> EXTEND_TO_KEYS = {
24 { DistributedData::SchemaMeta::DELETE_FIELD, "operation" },
25 { DistributedData::SchemaMeta::GID_FIELD, "id" },
26 { DistributedData::SchemaMeta::CREATE_FIELD, "createTime" },
27 { DistributedData::SchemaMeta::MODIFY_FIELD, "modifyTime" }
28 };
29
30 static std::set<std::string> EXTEND_KEYS = {
31 "operation",
32 "id",
33 "createTime",
34 "modifyTime"
35 };
36
CloudCursorImpl(OhCloudExtCloudDbData * cloudData)37 CloudCursorImpl::CloudCursorImpl(OhCloudExtCloudDbData *cloudData) : cloudData_(cloudData)
38 {
39 OhCloudExtCloudDbDataGetValues(cloudData_, &values_);
40 if (values_ == nullptr) {
41 return;
42 }
43 OhCloudExtVectorGetLength(values_, reinterpret_cast<unsigned int *>(&valuesLen_));
44 if (valuesLen_ > 0) {
45 void *values = nullptr;
46 size_t valueLen = 0;
47 auto status = OhCloudExtVectorGet(values_, 0, &values, reinterpret_cast<unsigned int *>(&valueLen));
48 if (status == ERRNO_SUCCESS && values != nullptr) {
49 OhCloudExtValueBucket *vBucket = reinterpret_cast<OhCloudExtValueBucket *>(values);
50 auto data = GetData(vBucket);
51 for (auto &[key, value] : data) {
52 names_.push_back(key);
53 }
54 OhCloudExtValueBucketFree(vBucket);
55 }
56 }
57 bool hasMore = false;
58 OhCloudExtCloudDbDataGetHasMore(cloudData_, &hasMore);
59 finished_ = !hasMore;
60 unsigned char *cursor = nullptr;
61 size_t cursorLen = 0;
62 auto status = OhCloudExtCloudDbDataGetNextCursor(
63 cloudData_, &cursor, reinterpret_cast<unsigned int *>(&cursorLen));
64 if (status == ERRNO_SUCCESS && cursor != nullptr) {
65 cursor_ = std::string(reinterpret_cast<char *>(cursor), cursorLen);
66 }
67 }
68
~CloudCursorImpl()69 CloudCursorImpl::~CloudCursorImpl()
70 {
71 if (cloudData_ != nullptr) {
72 OhCloudExtCloudDbDataFree(cloudData_);
73 cloudData_ = nullptr;
74 }
75 if (values_ != nullptr) {
76 OhCloudExtVectorFree(values_);
77 values_ = nullptr;
78 }
79 }
80
GetColumnNames(std::vector<std::string> & names) const81 int32_t CloudCursorImpl::GetColumnNames(std::vector<std::string> &names) const
82 {
83 if (values_ == nullptr) {
84 return DBErr::E_ALREADY_CLOSED;
85 }
86 names = names_;
87 return DBErr::E_OK;
88 }
89
GetColumnName(int32_t col,std::string & name) const90 int32_t CloudCursorImpl::GetColumnName(int32_t col, std::string &name) const
91 {
92 if (names_.size() <= static_cast<size_t>(col)) {
93 return DBErr::E_INVALID_ARGS;
94 }
95 name = names_[col];
96 return DBErr::E_OK;
97 }
98
GetColumnType(int32_t col) const99 int32_t CloudCursorImpl::GetColumnType(int32_t col) const
100 {
101 return DBErr::E_NOT_SUPPORT;
102 }
103
GetCount() const104 int32_t CloudCursorImpl::GetCount() const
105 {
106 return static_cast<int32_t>(valuesLen_);
107 }
108
MoveToFirst()109 int32_t CloudCursorImpl::MoveToFirst()
110 {
111 if (values_ == nullptr) {
112 return DBErr::E_ALREADY_CLOSED;
113 }
114 if (index_ != INVALID_INDEX || valuesLen_ == 0) {
115 return DBErr::E_ALREADY_CONSUMED;
116 }
117 index_ = 0;
118 consumed_ = false;
119 return DBErr::E_OK;
120 }
121
MoveToNext()122 int32_t CloudCursorImpl::MoveToNext()
123 {
124 if (values_ == nullptr) {
125 return DBErr::E_ALREADY_CLOSED;
126 }
127 if (index_ >= valuesLen_) {
128 return DBErr::E_ALREADY_CONSUMED;
129 }
130 if (index_ == INVALID_INDEX) {
131 index_ = 0;
132 } else {
133 ++index_;
134 }
135 consumed_ = false;
136 return DBErr::E_OK;
137 }
138
MoveToPrev()139 int32_t CloudCursorImpl::MoveToPrev()
140 {
141 return DBErr::E_NOT_SUPPORT;
142 }
143
GetEntry(DBVBucket & entry)144 int32_t CloudCursorImpl::GetEntry(DBVBucket &entry)
145 {
146 if (index_ == INVALID_INDEX) {
147 return DBErr::E_NOT_INIT;
148 }
149 if (consumed_ || index_ >= valuesLen_) {
150 return DBErr::E_ALREADY_CONSUMED;
151 }
152 void *values = nullptr;
153 size_t valueLen = 0;
154 auto status = OhCloudExtVectorGet(values_, index_, &values, reinterpret_cast<unsigned int *>(&valueLen));
155 if (status != ERRNO_SUCCESS || values == nullptr) {
156 return DBErr::E_ERROR;
157 }
158 OhCloudExtValueBucket *vBucket = reinterpret_cast<OhCloudExtValueBucket *>(values);
159 auto data = GetData(vBucket);
160 for (auto &[key, value] : data) {
161 entry[key] = value;
162 }
163 entry[DBSchemaMeta::DELETE_FIELD] = GetExtend(vBucket, OPERATION_KEY);
164 entry[DBSchemaMeta::GID_FIELD] = GetExtend(vBucket, GID_KEY);
165 entry[DBSchemaMeta::CREATE_FIELD] = GetExtend(vBucket, CREATE_TIME_KEY);
166 entry[DBSchemaMeta::MODIFY_FIELD] = GetExtend(vBucket, MODIFY_TIME_KEY);
167 entry[DBSchemaMeta::CURSOR_FIELD] = cursor_;
168 consumed_ = true;
169 OhCloudExtValueBucketFree(vBucket);
170 return DBErr::E_OK;
171 }
172
GetData(OhCloudExtValueBucket * vb)173 std::vector<std::pair<std::string, DBValue>> CloudCursorImpl::GetData(OhCloudExtValueBucket *vb)
174 {
175 std::vector<std::pair<std::string, DBValue>> result {};
176 OhCloudExtVector *keys = nullptr;
177 size_t keysLen = 0;
178 auto status = OhCloudExtValueBucketGetKeys(vb, &keys, reinterpret_cast<unsigned int *>(&keysLen));
179 if (status != ERRNO_SUCCESS || keys == nullptr) {
180 return result;
181 }
182 auto pKeys = std::shared_ptr<OhCloudExtVector>(keys, [](auto *keys) { OhCloudExtVectorFree(keys); });
183 for (size_t i = 0; i < keysLen; i++) {
184 void *value = nullptr;
185 size_t valueLen = 0;
186 auto status = OhCloudExtVectorGet(pKeys.get(), i, &value, reinterpret_cast<unsigned int *>(&valueLen));
187 if (status != ERRNO_SUCCESS && value == nullptr) {
188 return result;
189 }
190 char *str = reinterpret_cast<char *>(value);
191 auto key = std::string(str, valueLen);
192 if (EXTEND_KEYS.find(key) != EXTEND_KEYS.end()) {
193 continue;
194 }
195 auto dBValue = ExtensionUtil::ConvertValues(vb, key);
196 if (dBValue.index() == TYPE_INDEX<std::monostate>) {
197 continue;
198 }
199 std::pair<std::string, DBValue> data { std::move(key), std::move(dBValue) };
200 result.push_back(std::move(data));
201 }
202 return result;
203 }
204
GetExtend(OhCloudExtValueBucket * vb,const std::string & col)205 DBValue CloudCursorImpl::GetExtend(OhCloudExtValueBucket *vb, const std::string &col)
206 {
207 DBValue result;
208 int32_t status = ERRNO_SUCCESS;
209 auto keyStr = reinterpret_cast<const unsigned char *>(col.c_str());
210 OhCloudExtKeyName keyName = OhCloudExtKeyNameNew(keyStr, col.size());
211 OhCloudExtValueType type = OhCloudExtValueType::VALUEINNERTYPE_EMPTY;
212 void *content = nullptr;
213 size_t ctLen = 0;
214 status = OhCloudExtValueBucketGetValue(vb, keyName, &type, &content, reinterpret_cast<unsigned int *>(&ctLen));
215 if (status != ERRNO_SUCCESS || content == nullptr) {
216 return result;
217 }
218 if (col == OPERATION_KEY) {
219 auto flag = *reinterpret_cast<int *>(content);
220 result = (flag == DELETE) ? true : false;
221 } else if (col == GID_KEY) {
222 result = std::string(reinterpret_cast<char *>(content), ctLen);
223 } else if (col == CREATE_TIME_KEY) {
224 std::string createTime = std::string(reinterpret_cast<char *>(content), ctLen);
225 int64_t create = strtoll(createTime.c_str(), nullptr, 10);
226 result = create;
227 } else if (col == MODIFY_TIME_KEY) {
228 std::string modifyTime = std::string(reinterpret_cast<char *>(content), ctLen);
229 int64_t modify = strtoll(modifyTime.c_str(), nullptr, 10);
230 result = modify;
231 }
232 return result;
233 }
234
GetRow(DBVBucket & data)235 int32_t CloudCursorImpl::GetRow(DBVBucket &data)
236 {
237 return GetEntry(data);
238 }
239
Get(int32_t col,DBValue & value)240 int32_t CloudCursorImpl::Get(int32_t col, DBValue &value)
241 {
242 if (index_ == INVALID_INDEX) {
243 return DBErr::E_NOT_INIT;
244 }
245 if (names_.size() <= static_cast<size_t>(col)) {
246 return DBErr::E_INVALID_ARGS;
247 }
248 return Get(names_[col], value);
249 }
250
Get(const std::string & col,DBValue & value)251 int32_t CloudCursorImpl::Get(const std::string &col, DBValue &value)
252 {
253 if (col == DBSchemaMeta::CURSOR_FIELD) {
254 value = cursor_;
255 return DBErr::E_OK;
256 }
257 if (index_ == INVALID_INDEX) {
258 return DBErr::E_NOT_INIT;
259 }
260 if (consumed_ || index_ >= valuesLen_) {
261 return DBErr::E_ALREADY_CONSUMED;
262 }
263
264 void *data = nullptr;
265 size_t valueLen = 0;
266 auto status = OhCloudExtVectorGet(values_, index_, &data, reinterpret_cast<unsigned int *>(&valueLen));
267 if (status != ERRNO_SUCCESS || data == nullptr) {
268 return DBErr::E_ERROR;
269 }
270 OhCloudExtValueBucket *vBucket = reinterpret_cast<OhCloudExtValueBucket *>(data);
271 auto it = std::find(names_.begin(), names_.end(), col);
272 if (it == names_.end()) {
273 value = GetExtend(vBucket, EXTEND_TO_KEYS[col]);
274 OhCloudExtValueBucketFree(vBucket);
275 return DBErr::E_OK;
276 }
277 auto pair = GetData(vBucket);
278 OhCloudExtValueBucketFree(vBucket);
279 for (auto &[first, second] : pair) {
280 if (first == col) {
281 value = second;
282 return DBErr::E_OK;
283 }
284 }
285 return DBErr::E_INVALID_ARGS;
286 }
287
Close()288 int32_t CloudCursorImpl::Close()
289 {
290 if (cloudData_ != nullptr) {
291 OhCloudExtCloudDbDataFree(cloudData_);
292 cloudData_ = nullptr;
293 }
294 if (values_ != nullptr) {
295 OhCloudExtVectorFree(values_);
296 values_ = nullptr;
297 }
298 index_ = INVALID_INDEX;
299 return DBErr::E_OK;
300 }
301
IsEnd()302 bool CloudCursorImpl::IsEnd()
303 {
304 return finished_;
305 }
306 } // namespace OHOS::CloudData