• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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