1 /*
2 * Copyright (c) 2021 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 #include "query_sync_object.h"
17
18 #include "db_common.h"
19 #include "db_errno.h"
20 #include "log_print.h"
21 #include "version.h"
22
23 namespace DistributedDB {
24 namespace {
25 const std::string MAGIC = "remote query";
26 // Max value size of each QueryObjNode, current is In & NotIn predicate which is 128
27 const int MAX_VALUE_SIZE = 128;
28 const int MAX_QUERY_NODE_SIZE = 256;
29
SerializeDataObjNode(Parcel & parcel,const QueryObjNode & objNode)30 int SerializeDataObjNode(Parcel &parcel, const QueryObjNode &objNode)
31 {
32 if (objNode.operFlag == QueryObjType::OPER_ILLEGAL) {
33 return -E_INVALID_QUERY_FORMAT;
34 }
35 (void)parcel.WriteUInt32(static_cast<uint32_t>(objNode.operFlag));
36 parcel.EightByteAlign();
37 (void)parcel.WriteString(objNode.fieldName);
38 (void)parcel.WriteInt(static_cast<int32_t>(objNode.type));
39 (void)parcel.WriteUInt32(objNode.fieldValue.size());
40
41 for (const FieldValue &value : objNode.fieldValue) {
42 (void)parcel.WriteString(value.stringValue);
43
44 // string may not closely arranged continuously
45 // longValue is maximum length in union
46 (void)parcel.WriteInt64(value.longValue);
47 }
48 if (parcel.IsError()) {
49 return -E_INVALID_ARGS;
50 }
51 return E_OK;
52 }
53
DeSerializeDataObjNode(Parcel & parcel,QueryObjNode & objNode)54 int DeSerializeDataObjNode(Parcel &parcel, QueryObjNode &objNode)
55 {
56 uint32_t readOperFlag = 0;
57 (void)parcel.ReadUInt32(readOperFlag);
58 objNode.operFlag = static_cast<QueryObjType>(readOperFlag);
59 parcel.EightByteAlign();
60
61 (void)parcel.ReadString(objNode.fieldName);
62
63 int readInt = -1;
64 (void)parcel.ReadInt(readInt);
65 objNode.type = static_cast<QueryValueType>(readInt);
66
67 uint32_t valueSize = 0;
68 (void)parcel.ReadUInt32(valueSize);
69 if (parcel.IsError() || valueSize > MAX_VALUE_SIZE) {
70 return -E_INVALID_ARGS;
71 }
72
73 for (size_t i = 0; i < valueSize; i++) {
74 FieldValue value;
75 (void)parcel.ReadString(value.stringValue);
76
77 (void)parcel.ReadInt64(value.longValue);
78 if (parcel.IsError()) {
79 return -E_INVALID_ARGS;
80 }
81 objNode.fieldValue.push_back(value);
82 }
83 return E_OK;
84 }
85 }
86
QuerySyncObject()87 QuerySyncObject::QuerySyncObject()
88 {}
89
QuerySyncObject(const std::list<QueryObjNode> & queryObjNodes,const std::vector<uint8_t> & prefixKey,const std::set<Key> & keys)90 QuerySyncObject::QuerySyncObject(const std::list<QueryObjNode> &queryObjNodes, const std::vector<uint8_t> &prefixKey,
91 const std::set<Key> &keys)
92 : QueryObject(queryObjNodes, prefixKey, keys)
93 {}
94
QuerySyncObject(const Query & query)95 QuerySyncObject::QuerySyncObject(const Query &query)
96 : QueryObject(query)
97 {}
98
~QuerySyncObject()99 QuerySyncObject::~QuerySyncObject()
100 {}
101
GetVersion() const102 uint32_t QuerySyncObject::GetVersion() const
103 {
104 uint32_t version = QUERY_SYNC_OBJECT_VERSION_0;
105 if (isTableNameSpecified_ || !keys_.empty()) {
106 version = QUERY_SYNC_OBJECT_VERSION_1;
107 }
108 return version;
109 }
110
GetObjContext(ObjContext & objContext) const111 int QuerySyncObject::GetObjContext(ObjContext &objContext) const
112 {
113 if (!isValid_) {
114 return -E_INVALID_QUERY_FORMAT;
115 }
116 objContext.version = GetVersion();
117 objContext.prefixKey.assign(prefixKey_.begin(), prefixKey_.end());
118 objContext.suggestIndex = suggestIndex_;
119 objContext.queryObjNodes = queryObjNodes_;
120 return E_OK;
121 }
122
CalculateIdentifyLen() const123 uint32_t QuerySyncObject::CalculateIdentifyLen() const
124 {
125 uint64_t len = Parcel::GetVectorCharLen(prefixKey_);
126 for (const QueryObjNode &node : queryObjNodes_) {
127 if (node.operFlag == QueryObjType::LIMIT || node.operFlag == QueryObjType::ORDERBY ||
128 node.operFlag == QueryObjType::SUGGEST_INDEX) {
129 continue;
130 }
131 // operFlag and valueType is int
132 len += Parcel::GetUInt32Len() + Parcel::GetIntLen() + Parcel::GetStringLen(node.fieldName);
133 for (const FieldValue &value : node.fieldValue) {
134 len += Parcel::GetStringLen(value.stringValue) + Parcel::GetInt64Len();
135 }
136 }
137
138 // QUERY_SYNC_OBJECT_VERSION_1 added.
139 len += isTableNameSpecified_ ? Parcel::GetStringLen(tableName_) : 0;
140 for (const auto &key : keys_) {
141 len += Parcel::GetVectorCharLen(key);
142 } // QUERY_SYNC_OBJECT_VERSION_1 end.
143 return len;
144 }
145
GetIdentify() const146 std::string QuerySyncObject::GetIdentify() const
147 {
148 if (!isValid_) {
149 return std::string();
150 }
151 if (!identify_.empty()) {
152 return identify_;
153 }
154 // suggestionIndex is local attribute, do not need to be propagated to remote
155 uint64_t len = CalculateIdentifyLen();
156 std::vector<uint8_t> buff(len, 0); // It will affect the hash result, the default value cannot be modified
157 Parcel parcel(buff.data(), len);
158
159 // The order needs to be consistent, otherwise it will affect the hash result
160 (void)parcel.WriteVectorChar(prefixKey_);
161 for (const QueryObjNode &node : queryObjNodes_) {
162 if (node.operFlag == QueryObjType::LIMIT || node.operFlag == QueryObjType::ORDERBY ||
163 node.operFlag == QueryObjType::SUGGEST_INDEX) {
164 continue;
165 }
166 (void)parcel.WriteUInt32(static_cast<uint32_t>(node.operFlag));
167 (void)parcel.WriteInt(static_cast<int32_t>(node.type));
168 (void)parcel.WriteString(node.fieldName);
169 for (const FieldValue &value : node.fieldValue) {
170 (void)parcel.WriteInt64(value.longValue);
171 (void)parcel.WriteString(value.stringValue);
172 }
173 }
174
175 // QUERY_SYNC_OBJECT_VERSION_1 added.
176 if (isTableNameSpecified_) {
177 (void)parcel.WriteString(tableName_);
178 }
179 for (const auto &key : keys_) {
180 (void)parcel.WriteVectorChar(key);
181 } // QUERY_SYNC_OBJECT_VERSION_1 end.
182
183 std::vector<uint8_t> hashBuff;
184 if (parcel.IsError() || DBCommon::CalcValueHash(buff, hashBuff) != E_OK) {
185 return std::string();
186 }
187 identify_ = DBCommon::VectorToHexString(hashBuff);
188 return identify_;
189 }
190
CalculateParcelLen(uint32_t softWareVersion) const191 uint32_t QuerySyncObject::CalculateParcelLen(uint32_t softWareVersion) const
192 {
193 if (softWareVersion == SOFTWARE_VERSION_CURRENT) {
194 return CalculateLen();
195 }
196 LOGE("current not support!");
197 return 0;
198 }
199
SerializeData(Parcel & parcel,uint32_t softWareVersion)200 int QuerySyncObject::SerializeData(Parcel &parcel, uint32_t softWareVersion)
201 {
202 ObjContext context;
203 int errCode = GetObjContext(context);
204 if (errCode != E_OK) {
205 return errCode;
206 }
207 (void)parcel.WriteString(MAGIC);
208 (void)parcel.WriteUInt32(context.version);
209 (void)parcel.WriteVectorChar(context.prefixKey);
210 (void)parcel.WriteString(context.suggestIndex);
211 (void)parcel.WriteUInt32(context.queryObjNodes.size());
212 parcel.EightByteAlign();
213 if (parcel.IsError()) {
214 return -E_INVALID_ARGS;
215 }
216 for (const QueryObjNode &node : context.queryObjNodes) {
217 errCode = SerializeDataObjNode(parcel, node);
218 if (errCode != E_OK) {
219 return errCode;
220 }
221 }
222
223 // QUERY_SYNC_OBJECT_VERSION_1 added.
224 if (context.version >= QUERY_SYNC_OBJECT_VERSION_1) {
225 (void)parcel.WriteUInt32(static_cast<uint32_t>(isTableNameSpecified_));
226 if (isTableNameSpecified_) {
227 (void)parcel.WriteString(tableName_);
228 }
229 (void)parcel.WriteUInt32(keys_.size());
230 for (const auto &key : keys_) {
231 (void)parcel.WriteVectorChar(key);
232 }
233 } // QUERY_SYNC_OBJECT_VERSION_1 end.
234 parcel.EightByteAlign();
235 if (parcel.IsError()) { // parcel almost success
236 return -E_INVALID_ARGS;
237 }
238 return E_OK;
239 }
240
241 namespace {
DeSerializeVersion1Data(uint32_t version,Parcel & parcel,std::string & tableName,std::set<Key> & keys)242 int DeSerializeVersion1Data(uint32_t version, Parcel &parcel, std::string &tableName, std::set<Key> &keys)
243 {
244 if (version >= QUERY_SYNC_OBJECT_VERSION_1) {
245 uint32_t isTblNameExist = 0;
246 (void)parcel.ReadUInt32(isTblNameExist);
247 if (isTblNameExist) {
248 (void)parcel.ReadString(tableName);
249 }
250 uint32_t keysSize = 0;
251 (void)parcel.ReadUInt32(keysSize);
252 if (keysSize > DBConstant::MAX_INKEYS_SIZE) {
253 return -E_PARSE_FAIL;
254 }
255 for (uint32_t i = 0; i < keysSize; ++i) {
256 Key key;
257 (void)parcel.ReadVector(key);
258 keys.emplace(key);
259 }
260 }
261 return E_OK;
262 }
263 }
264
DeSerializeData(Parcel & parcel,QuerySyncObject & queryObj)265 int QuerySyncObject::DeSerializeData(Parcel &parcel, QuerySyncObject &queryObj)
266 {
267 std::string magic;
268 (void)parcel.ReadString(magic);
269 if (magic != MAGIC) {
270 return -E_INVALID_ARGS;
271 }
272
273 ObjContext context;
274 (void)parcel.ReadUInt32(context.version);
275 if (context.version > QUERY_SYNC_OBJECT_VERSION_CURRENT) {
276 LOGE("Parcel version and deserialize version not matched! ver=%u", context.version);
277 return -E_VERSION_NOT_SUPPORT;
278 }
279
280 (void)parcel.ReadVectorChar(context.prefixKey);
281 (void)parcel.ReadString(context.suggestIndex);
282
283 uint32_t nodesSize = 0;
284 (void)parcel.ReadUInt32(nodesSize);
285 parcel.EightByteAlign();
286 // Due to historical reasons, the limit of query node size was incorrectly set to MAX_QUERY_NODE_SIZE + 1
287 if (parcel.IsError() || nodesSize > MAX_QUERY_NODE_SIZE + 1) { // almost success
288 return -E_INVALID_ARGS;
289 }
290 for (size_t i = 0; i < nodesSize; i++) {
291 QueryObjNode node;
292 int errCode = DeSerializeDataObjNode(parcel, node);
293 if (errCode != E_OK) {
294 return errCode;
295 }
296 context.queryObjNodes.emplace_back(node);
297 }
298
299 // QUERY_SYNC_OBJECT_VERSION_1 added.
300 std::string tableName;
301 std::set<Key> keys;
302 int errCode = DeSerializeVersion1Data(context.version, parcel, tableName, keys);
303 if (errCode != E_OK) {
304 return errCode;
305 } // QUERY_SYNC_OBJECT_VERSION_1 end.
306
307 if (parcel.IsError()) { // almost success
308 return -E_INVALID_ARGS;
309 }
310 queryObj = QuerySyncObject(context.queryObjNodes, context.prefixKey, keys);
311 if (!tableName.empty()) {
312 queryObj.SetTableName(tableName);
313 }
314 return E_OK;
315 }
316
CalculateLen() const317 uint32_t QuerySyncObject::CalculateLen() const
318 {
319 uint64_t len = Parcel::GetStringLen(MAGIC);
320 len += Parcel::GetUInt32Len(); // version
321 len += Parcel::GetVectorCharLen(prefixKey_);
322 len += Parcel::GetStringLen(suggestIndex_);
323 len += Parcel::GetUInt32Len(); // nodes size
324 len = Parcel::GetEightByteAlign(len);
325 for (const QueryObjNode &node : queryObjNodes_) {
326 if (node.operFlag == QueryObjType::OPER_ILLEGAL) {
327 LOGE("contain illegal operator for query sync!");
328 return 0;
329 }
330 // operflag, fieldName, query value type, value size, union max size, string value
331 len += Parcel::GetUInt32Len();
332 len = Parcel::GetEightByteAlign(len);
333 len += Parcel::GetStringLen(node.fieldName) +
334 Parcel::GetIntLen() + Parcel::GetUInt32Len();
335 for (size_t i = 0; i < node.fieldValue.size(); i++) {
336 len += Parcel::GetInt64Len() + Parcel::GetStringLen(node.fieldValue[i].stringValue);
337 }
338 }
339
340 // QUERY_SYNC_OBJECT_VERSION_1 added.
341 len += Parcel::GetUInt32Len(); // whether the table name exists.
342 if (isTableNameSpecified_) {
343 len += Parcel::GetStringLen(tableName_);
344 }
345 len += Parcel::GetUInt32Len(); // size of keys_
346 for (const auto &key : keys_) {
347 len += Parcel::GetVectorCharLen(key);
348 } // QUERY_SYNC_OBJECT_VERSION_1 end.
349
350 len = Parcel::GetEightByteAlign(len);
351 if (len > INT32_MAX) {
352 return 0;
353 }
354 return static_cast<uint32_t>(len);
355 }
356
GetRelationTableName() const357 std::string QuerySyncObject::GetRelationTableName() const
358 {
359 if (!isTableNameSpecified_) {
360 return {};
361 }
362 return tableName_;
363 }
364
GetRelationTableNames() const365 std::vector<std::string> QuerySyncObject::GetRelationTableNames() const
366 {
367 return tables_;
368 }
369
GetIsDeviceSyncQuery() const370 bool QuerySyncObject::GetIsDeviceSyncQuery() const
371 {
372 return isWithDeviceSyncQuery_;
373 }
374 } // namespace DistributedDB