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