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