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 #include "result_set.h"
16
17 #include "document_key.h"
18 #include "rd_db_constant.h"
19 #include "rd_log_print.h"
20 #include "securec.h"
21
22 namespace DocumentDB {
23 constexpr const char *KEY_ID = "_id";
24
ResultSet()25 ResultSet::ResultSet() {}
~ResultSet()26 ResultSet::~ResultSet()
27 {
28 context_ = nullptr;
29 }
EraseCollection()30 int ResultSet::EraseCollection()
31 {
32 if (store_ != nullptr) {
33 store_->EraseCollection(context_->collectionName);
34 }
35 return E_OK;
36 }
Init(std::shared_ptr<QueryContext> & context,DocumentStore * store,bool isCutBranch)37 int ResultSet::Init(std::shared_ptr<QueryContext> &context, DocumentStore *store, bool isCutBranch)
38 {
39 isCutBranch_ = isCutBranch;
40 context_ = context;
41 store_ = store;
42 return E_OK;
43 }
44
GetValueFromDB(Key & key,JsonObject & filterObj,std::string & jsonKey,std::string & jsonData)45 int ResultSet::GetValueFromDB(Key &key, JsonObject &filterObj, std::string &jsonKey, std::string &jsonData)
46 {
47 std::pair<std::string, std::string> value;
48 Collection coll = store_->GetCollection(context_->collectionName);
49 filterObj.DeleteItemFromObject(KEY_ID);
50 int errCode = coll.GetMatchedDocument(filterObj, key, value, context_->isIdExist);
51 if (errCode == -E_NOT_FOUND) {
52 return -E_NO_DATA;
53 }
54 jsonData.assign(value.second.begin(), value.second.end());
55 jsonKey.assign(value.first.begin(), value.first.end());
56 lastKeyIndex_ = jsonKey;
57 if (isCutBranch_) {
58 errCode = CutJsonBranch(jsonKey, jsonData);
59 if (errCode != E_OK) {
60 GLOGE("cut branch faild");
61 }
62 }
63 return errCode;
64 }
65
GetNextWithField()66 int ResultSet::GetNextWithField()
67 {
68 int errCode = E_OK;
69 JsonObject filterObj = JsonObject::Parse(context_->filter, errCode, true, true);
70 if (errCode != E_OK) {
71 GLOGE("filter Parsed failed");
72 return errCode;
73 }
74 Key key;
75 if (context_->isIdExist) {
76 if (index_ == 0) { // get id from filter, if alreay has got id once, get from lastKeyIndex.
77 JsonObject filterObjChild = filterObj.GetChild();
78 ValueObject idValue = JsonCommon::GetValueInSameLevel(filterObjChild, KEY_ID);
79 std::string idKey = idValue.GetStringValue();
80 key.assign(idKey.begin(), idKey.end());
81 } else { // Use id to find data that can only get one data.
82 matchData_.first.clear(); // Delete previous data.
83 matchData_.second.clear();
84 return -E_NO_DATA;
85 }
86 } else {
87 key.assign(lastKeyIndex_.begin(), lastKeyIndex_.end());
88 }
89 matchData_.first.clear();
90 matchData_.second.clear();
91 std::string jsonKey;
92 std::string jsonData;
93 errCode = GetValueFromDB(key, filterObj, jsonKey, jsonData);
94 matchData_ = std::make_pair(jsonKey, jsonData);
95 return errCode;
96 }
97
GetNextInner(bool isNeedCheckTable)98 int ResultSet::GetNextInner(bool isNeedCheckTable)
99 {
100 int errCode = E_OK;
101 if (isNeedCheckTable) {
102 std::string lowerCaseName = context_->collectionName;
103 std::transform(lowerCaseName.begin(), lowerCaseName.end(), lowerCaseName.begin(), [](unsigned char c) {
104 return std::tolower(c);
105 });
106 bool isCollectionExist = store_->IsCollectionExists(RdDBConstant::COLL_PREFIX + lowerCaseName, errCode);
107 if (errCode != E_OK) {
108 return errCode;
109 }
110 if (!isCollectionExist) {
111 return -E_INVALID_ARGS;
112 }
113 }
114 errCode = GetNextWithField();
115 index_++;
116 if (errCode != E_OK) {
117 return errCode;
118 }
119 if (matchData_.second.empty()) {
120 return -E_NO_DATA;
121 }
122 return E_OK;
123 }
124
GetNext(bool isNeedTransaction,bool isNeedCheckTable)125 int ResultSet::GetNext(bool isNeedTransaction, bool isNeedCheckTable)
126 {
127 if (!isNeedTransaction) {
128 return GetNextInner(isNeedCheckTable);
129 }
130 std::lock_guard<std::mutex> lock(store_->dbMutex_);
131 int errCode = store_->StartTransaction();
132 if (errCode != E_OK) {
133 GLOGE("Start transaction faild");
134 return errCode;
135 }
136 errCode = GetNextInner(isNeedCheckTable);
137 if (errCode == E_OK || errCode == -E_NO_DATA) {
138 store_->Commit();
139 } else {
140 store_->Rollback();
141 }
142 return errCode;
143 }
144
GetValue(char ** value)145 int ResultSet::GetValue(char **value)
146 {
147 std::lock_guard<std::mutex> lock(store_->dbMutex_);
148 if (matchData_.first.empty()) {
149 GLOGE("The value vector in resultSet is empty");
150 return -E_NO_DATA;
151 }
152 std::string jsonData = matchData_.second;
153 char *jsonstr = new char[jsonData.size() + 1];
154 if (jsonstr == nullptr) {
155 GLOGE("Memory allocation failed!");
156 return -E_FAILED_MEMORY_ALLOCATE;
157 }
158 int err = strcpy_s(jsonstr, jsonData.size() + 1, jsonData.c_str());
159 if (err != 0) {
160 GLOGE("strcpy_s failed");
161 delete[] jsonstr;
162 return -E_NO_DATA;
163 }
164 *value = jsonstr;
165 return E_OK;
166 }
167
GetValue(std::string & value)168 int ResultSet::GetValue(std::string &value)
169 {
170 if (matchData_.first.empty()) {
171 GLOGE("The value vector in resultSet is empty");
172 return -E_NO_DATA;
173 }
174 value = matchData_.second;
175 return E_OK;
176 }
177
GetKey(std::string & key)178 int ResultSet::GetKey(std::string &key)
179 {
180 key = matchData_.first;
181 if (key.empty()) {
182 GLOGE("can not get data, because it is empty");
183 return -E_NO_DATA;
184 }
185 return E_OK;
186 }
187
CheckCutNode(JsonObject * node,std::vector<std::string> singlePath,std::vector<std::vector<std::string>> & allCutPath)188 int ResultSet::CheckCutNode(JsonObject *node, std::vector<std::string> singlePath,
189 std::vector<std::vector<std::string>> &allCutPath)
190 {
191 if (node == nullptr) {
192 GLOGE("No node to cut");
193 return -E_NO_DATA;
194 }
195 JsonObject nodeInstance = *node;
196 while (!nodeInstance.IsNull()) {
197 singlePath.emplace_back(nodeInstance.GetItemField());
198 size_t index = 0;
199 bool isMatch = context_->projectionTree.SearchTree(singlePath, index);
200 if ((nodeInstance.GetType() == JsonObject::Type::JSON_ARRAY && isMatch && index == 0) ||
201 (!isMatch && index == 0)) {
202 allCutPath.emplace_back(singlePath);
203 }
204 if (nodeInstance.GetType() != JsonObject::Type::JSON_ARRAY && !nodeInstance.GetChild().IsNull()) {
205 JsonObject nodeChiled = nodeInstance.GetChild();
206 CheckCutNode(&nodeChiled, singlePath, allCutPath);
207 }
208 singlePath.pop_back();
209 nodeInstance = nodeInstance.GetNext();
210 }
211 return E_OK;
212 }
213
CreatIdObj(const std::string & idStr,int errCode)214 JsonObject CreatIdObj(const std::string &idStr, int errCode)
215 {
216 std::stringstream sstream;
217 sstream << "{\"_id\":"
218 << "\"" << idStr << "\"}";
219 JsonObject idObj = JsonObject::Parse(sstream.str(), errCode, true); // cant be faild.
220 return idObj;
221 }
222
InsertId(JsonObject & cjsonObj,const std::string & jsonKey)223 int InsertId(JsonObject &cjsonObj, const std::string &jsonKey)
224 {
225 if (jsonKey.empty()) {
226 GLOGE("Genalral Id faild");
227 return -E_INNER_ERROR;
228 }
229 int errCode = E_OK;
230 JsonObject idObj = CreatIdObj(jsonKey, errCode);
231 if (errCode != E_OK) {
232 GLOGE("CreatIdObj faild");
233 return errCode;
234 }
235 cjsonObj.InsertItemObject(0, idObj.GetChild()); // idObj's child is _id node
236 return E_OK;
237 }
238
CutJsonBranch(std::string & jsonKey,std::string & jsonData)239 int ResultSet::CutJsonBranch(std::string &jsonKey, std::string &jsonData)
240 {
241 int errCode;
242 JsonObject cjsonObj = JsonObject::Parse(jsonData, errCode, true);
243 if (errCode != E_OK) {
244 GLOGE("jsonData Parsed failed");
245 return errCode;
246 }
247 bool isIdExistInValue = true; // if id exsit in the value string that get from db.
248 bool isInsertIdflag = false;
249 isIdExistInValue = cjsonObj.GetObjectItem("_id", errCode).IsNull() ? false : true;
250 if (context_->ifShowId && !isIdExistInValue) {
251 isInsertIdflag = true; // ifShowId is true,and then the data taken out does not have IDs, insert id.
252 }
253 if (context_->viewType) {
254 std::vector<std::string> singlePath;
255 JsonObject cjsonObjChild = cjsonObj.GetChild();
256 std::vector<std::vector<std::string>> allCutPath;
257 errCode = CheckCutNode(&cjsonObjChild, singlePath, allCutPath);
258 if (errCode != E_OK) {
259 GLOGE("The node in CheckCutNode is nullptr");
260 return errCode;
261 }
262 for (const auto &singleCutPath : allCutPath) {
263 if (!context_->ifShowId || singleCutPath[0] != KEY_ID) {
264 cjsonObj.DeleteItemDeeplyOnTarget(singleCutPath);
265 }
266 if (singleCutPath[0] == KEY_ID && !isIdExistInValue) { // projection has Id, and its showType is true.
267 isInsertIdflag = true;
268 }
269 }
270 }
271 if (isInsertIdflag) {
272 errCode = InsertId(cjsonObj, jsonKey);
273 if (errCode != E_OK) {
274 return errCode;
275 }
276 }
277 if (!context_->viewType) {
278 for (const auto &singleCutPaht : context_->projectionPath) {
279 cjsonObj.DeleteItemDeeplyOnTarget(singleCutPaht);
280 }
281 if (!context_->ifShowId) {
282 std::vector<std::string> idPath;
283 idPath.emplace_back(KEY_ID);
284 cjsonObj.DeleteItemDeeplyOnTarget(idPath);
285 }
286 }
287 jsonData = cjsonObj.Print();
288 return E_OK;
289 }
290 } // namespace DocumentDB
291