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 "sqlite_single_ver_storage_executor.h"
17
18 #include "log_print.h"
19 #include "db_common.h"
20 #include "db_errno.h"
21 #include "sqlite_single_ver_storage_executor_sql.h"
22
23 namespace DistributedDB {
24 using namespace TriggerMode;
25
CheckQueryObjectLegal(QueryObject & queryObj) const26 int SQLiteSingleVerStorageExecutor::CheckQueryObjectLegal(QueryObject &queryObj) const
27 {
28 int errCode = E_OK;
29 SqliteQueryHelper helper = queryObj.GetQueryHelper(errCode);
30 if (errCode != E_OK) {
31 LOGE("Get query helper failed [%d]!", errCode);
32 return errCode;
33 }
34
35 sqlite3_stmt *statement = nullptr;
36 errCode = helper.GetQuerySyncStatement(dbHandle_, 0, INT64_MAX, statement); // (0, INT64_MAX):max range
37 int ret = E_OK;
38 SQLiteUtils::ResetStatement(statement, true, ret);
39 if (ret != E_OK) {
40 LOGW("Failed to reset statement. error:%d", ret);
41 }
42 return CheckCorruptedStatus(errCode);
43 }
44
CheckMissQueryDataItem(sqlite3_stmt * stmt,const std::string & deviceName,DataItem & item)45 int SQLiteSingleVerStorageExecutor::CheckMissQueryDataItem(sqlite3_stmt *stmt, const std::string &deviceName,
46 DataItem &item)
47 {
48 int errCode = SQLiteUtils::StepWithRetry(stmt, isMemDb_);
49 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
50 // the value with same hashKey in DB matched the query
51 std::vector<uint8_t> dev;
52 errCode = SQLiteUtils::GetColumnBlobValue(stmt, SYNC_RES_DEVICE_INDEX, dev);
53 if (errCode != E_OK) {
54 LOGE("Get data device info failed. %d", errCode);
55 return errCode;
56 }
57 auto timestamp = static_cast<Timestamp>(sqlite3_column_int64(stmt, SYNC_RES_TIME_INDEX));
58 std::string device = std::string(dev.begin(), dev.end());
59 // this data item should be neglected when it's out of date of it's from same device
60 // otherwise, it should be erased after resolved the conflict
61 item.neglect = (timestamp > item.timestamp) ||
62 (timestamp == item.timestamp && device == DBCommon::TransferHashString(deviceName));
63 return E_OK;
64 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
65 // the value with same hashKey in DB does not match the query, this data item should be neglected.
66 item.neglect = true;
67 return E_OK;
68 }
69 LOGE("Check sync data failed %d", errCode);
70 return errCode;
71 }
72
73 // check the data with REMOTE_DEVICE_DATA_MISS_QUERY flag need neglect or not
CheckMissQueryDataItems(sqlite3_stmt * & stmt,const SqliteQueryHelper & helper,const DeviceInfo & deviceInfo,std::vector<DataItem> & dataItems)74 int SQLiteSingleVerStorageExecutor::CheckMissQueryDataItems(sqlite3_stmt *&stmt, const SqliteQueryHelper &helper,
75 const DeviceInfo &deviceInfo, std::vector<DataItem> &dataItems)
76 {
77 int errCode = E_OK;
78 int ret = E_OK;
79 for (auto &item : dataItems) {
80 if ((item.flag & DataItem::REMOTE_DEVICE_DATA_MISS_QUERY) != 0 && !item.key.empty()) {
81 errCode = helper.BindSyncDataCheckStmt(stmt, item.key);
82 if (errCode != E_OK) {
83 LOGE("Bind sync data check statement failed %d", errCode);
84 break;
85 }
86 errCode = CheckMissQueryDataItem(stmt, deviceInfo.deviceName, item);
87 if (errCode != E_OK) {
88 LOGE("Check miss query data item failed. %d", errCode);
89 return errCode;
90 }
91 SQLiteUtils::ResetStatement(stmt, false, ret);
92 }
93 }
94 return errCode != E_OK ? errCode : ret;
95 }
96
CheckDataWithQuery(QueryObject query,std::vector<DataItem> & dataItems,const DeviceInfo & deviceInfo)97 int SQLiteSingleVerStorageExecutor::CheckDataWithQuery(QueryObject query, std::vector<DataItem> &dataItems,
98 const DeviceInfo &deviceInfo)
99 {
100 int errCode = E_OK;
101 if (query.Empty()) {
102 LOGD("Query is empty, skip check.");
103 return E_OK;
104 }
105 SqliteQueryHelper helper = query.GetQueryHelper(errCode);
106 if (errCode != E_OK) {
107 LOGE("Get query helper failed [%d]!", errCode);
108 return errCode;
109 }
110 std::string sql;
111 errCode = helper.GetSyncDataCheckSql(sql);
112 if (errCode != E_OK) {
113 LOGE("Get sync data check sql failed");
114 return errCode;
115 }
116 sqlite3_stmt *stmt = nullptr;
117 errCode = SQLiteUtils::GetStatement(dbHandle_, sql, stmt);
118 if (errCode != E_OK) {
119 LOGE("Get statement fail. %d", errCode);
120 return -E_INVALID_QUERY_FORMAT;
121 }
122 errCode = CheckMissQueryDataItems(stmt, helper, deviceInfo, dataItems);
123 if (errCode != E_OK) {
124 LOGE("check data with query failed. %d", errCode);
125 }
126 int ret = E_OK;
127 SQLiteUtils::ResetStatement(stmt, true, ret);
128 return CheckCorruptedStatus(errCode);
129 }
130
131 namespace {
FormatSubscribeTriggerSql(const std::string & subscribeId,const std::string & subscribeCondition,TriggerModeEnum mode)132 std::string FormatSubscribeTriggerSql(const std::string &subscribeId, const std::string &subscribeCondition,
133 TriggerModeEnum mode)
134 {
135 std::string triggerModeString = GetTriggerModeString(mode);
136 std::string accessString = ((mode == TriggerModeEnum::DELETE) ?
137 DBConstant::TRIGGER_REFERENCES_OLD : DBConstant::TRIGGER_REFERENCES_NEW);
138 std::string keyStr = DBConstant::SUBSCRIBE_QUERY_PREFIX + DBCommon::TransferHashString(subscribeId);
139 Key key {keyStr.begin(), keyStr.end()};
140 std::string hexKeyStr = DBCommon::VectorToHexString(key);
141 std::string triggerName = DBConstant::SUBSCRIBE_QUERY_PREFIX + subscribeId + "_ON_" + triggerModeString;
142 return "CREATE TRIGGER IF NOT EXISTS " + triggerName + " AFTER " + triggerModeString + " \n"
143 "ON sync_data\n"
144 "WHEN ((NEW.flag&0x02=0x02) AND (" + subscribeCondition + "))\n" // filter locally changed data
145 "BEGIN\n"
146 " SELECT " + DBConstant::UPDATE_META_FUNC + "(x'" + hexKeyStr + "', NEW.TIMESTAMP);\n"
147 "END;";
148 }
149 }
150
AddSubscribeTrigger(QueryObject & query,const std::string & subscribeId)151 int SQLiteSingleVerStorageExecutor::AddSubscribeTrigger(QueryObject &query, const std::string &subscribeId)
152 {
153 if (executorState_ == ExecutorState::CACHEDB || executorState_ == ExecutorState::CACHE_ATTACH_MAIN) {
154 LOGE("Not support add subscribe in cache db.");
155 return -E_EKEYREVOKED;
156 }
157 int errCode = E_OK;
158 SqliteQueryHelper helper = query.GetQueryHelper(errCode);
159 if (errCode != E_OK) {
160 LOGE("Get query helper failed. %d", errCode);
161 return errCode;
162 }
163 // check if sqlite function is registered or not
164 sqlite3_stmt *stmt = nullptr;
165 errCode = SQLiteUtils::GetStatement(dbHandle_,
166 "SELECT " + std::string(DBConstant::UPDATE_META_FUNC) + "('K', 0);", stmt);
167 if (errCode != E_OK) {
168 LOGE("sqlite function update_meta_within_trigger has not been created.");
169 return -E_NOT_SUPPORT;
170 }
171 SQLiteUtils::ResetStatement(stmt, true, errCode);
172
173 // Delete data API is actually an update operation, there is no need for DELETE trigger
174 for (auto mode : {TriggerModeEnum::INSERT, TriggerModeEnum::UPDATE}) {
175 std::string subscribeCondition;
176 errCode = helper.GetSubscribeSql(mode, subscribeCondition);
177 if (errCode != E_OK) {
178 LOGE("Get subscribe trigger create sql failed. mode: %d, errCode: %d", static_cast<int>(mode),
179 errCode);
180 return errCode;
181 }
182 std::string sql = FormatSubscribeTriggerSql(subscribeId, subscribeCondition, mode);
183 errCode = SQLiteUtils::ExecuteRawSQL(dbHandle_, sql);
184 if (errCode != E_OK) {
185 LOGE("Add subscribe trigger failed. mode: %d, errCode: %d", static_cast<int>(mode), errCode);
186 return errCode;
187 }
188 }
189 return E_OK;
190 }
191
RemoveSubscribeTrigger(const std::vector<std::string> & subscribeIds)192 int SQLiteSingleVerStorageExecutor::RemoveSubscribeTrigger(const std::vector<std::string> &subscribeIds)
193 {
194 int errCode = E_OK;
195 for (const auto &id : subscribeIds) {
196 for (auto mode : {TriggerModeEnum::INSERT, TriggerModeEnum::UPDATE}) {
197 const std::string trigger = DBConstant::SUBSCRIBE_QUERY_PREFIX + id + "_ON_" + GetTriggerModeString(mode);
198 errCode = SQLiteUtils::DropTriggerByName(dbHandle_, trigger);
199 if (errCode != E_OK) {
200 LOGE("remove subscribe trigger failed. %d", errCode);
201 break;
202 }
203 }
204 if (errCode != E_OK) {
205 LOGE("remove subscribe trigger failed. %d", errCode);
206 break;
207 }
208 }
209 return errCode;
210 }
211
RemoveTrigger(const std::vector<std::string> & triggers)212 int SQLiteSingleVerStorageExecutor::RemoveTrigger(const std::vector<std::string> &triggers)
213 {
214 int errCode = E_OK;
215 for (const auto &trigger : triggers) {
216 errCode = SQLiteUtils::DropTriggerByName(dbHandle_, trigger);
217 if (errCode != E_OK) {
218 LOGE("remove trigger failed. %d", errCode);
219 break;
220 }
221 }
222 return errCode;
223 }
224
RemoveSubscribeTriggerWaterMark(const std::vector<std::string> & subscribeIds)225 int SQLiteSingleVerStorageExecutor::RemoveSubscribeTriggerWaterMark(const std::vector<std::string> &subscribeIds)
226 {
227 sqlite3_stmt *statement = nullptr;
228 const std::string sql = attachMetaMode_ ? REMOVE_ATTACH_META_VALUE_SQL : REMOVE_META_VALUE_SQL;
229 int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, statement);
230 if (errCode != E_OK) {
231 LOGE("Get remove trigger water mark statement failed. %d", errCode);
232 return errCode;
233 }
234 int ret = E_OK;
235 for (const auto &id : subscribeIds) {
236 errCode = SQLiteUtils::BindTextToStatement(statement, 1, DBConstant::SUBSCRIBE_QUERY_PREFIX + id);
237 if (errCode != E_OK) {
238 LOGE("Bind mark key to statement failed. %d", errCode);
239 break;
240 }
241 errCode = SQLiteUtils::StepWithRetry(statement, isMemDb_);
242 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
243 errCode = E_OK;
244 } else {
245 LOGE("Remove trigger water mark failed. %d", errCode);
246 break;
247 }
248 SQLiteUtils::ResetStatement(statement, false, ret);
249 }
250 SQLiteUtils::ResetStatement(statement, true, ret);
251 return errCode != E_OK ? errCode : ret;
252 }
253
GetTriggers(const std::string & namePreFix,std::vector<std::string> & triggerNames)254 int SQLiteSingleVerStorageExecutor::GetTriggers(const std::string &namePreFix, std::vector<std::string> &triggerNames)
255 {
256 sqlite3_stmt *stmt = nullptr;
257 int errCode = SQLiteUtils::GetStatement(dbHandle_, GET_SYNC_DATA_TIRGGER_SQL, stmt);
258 if (errCode != E_OK) {
259 LOGE("Get trigger query statement failed. %d", errCode);
260 return errCode;
261 }
262
263 int ret = E_OK;
264 errCode = SQLiteUtils::BindTextToStatement(stmt, 1, namePreFix + "%");
265 if (errCode != E_OK) {
266 SQLiteUtils::ResetStatement(stmt, true, ret);
267 LOGE("Bind trigger name prefix to statement failed. %d", errCode);
268 return errCode;
269 }
270
271 do {
272 errCode = SQLiteUtils::StepWithRetry(stmt, isMemDb_);
273 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
274 errCode = E_OK;
275 break;
276 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
277 std::string name;
278 SQLiteUtils::GetColumnTextValue(stmt, 0, name);
279 triggerNames.emplace_back(name);
280 } else {
281 LOGE("Get trigger by name prefix failed. %d", errCode);
282 break;
283 }
284 } while (true);
285
286 SQLiteUtils::ResetStatement(stmt, true, ret);
287 return errCode != E_OK ? errCode : ret;
288 }
289 } // namespace DistributedDB
290