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     for (auto &item : dataItems) {
79         if ((item.flag & DataItem::REMOTE_DEVICE_DATA_MISS_QUERY) != 0 && !item.key.empty()) {
80             errCode = helper.BindSyncDataCheckStmt(stmt, item.key);
81             if (errCode != E_OK) {
82                 LOGE("Bind sync data check statement failed %d", errCode);
83                 break;
84             }
85             errCode = CheckMissQueryDataItem(stmt, deviceInfo.deviceName, item);
86             if (errCode != E_OK) {
87                 LOGE("Check miss query data item failed. %d", errCode);
88                 return errCode;
89             }
90             SQLiteUtils::ResetStatement(stmt, false, errCode);
91         }
92     }
93     return errCode;
94 }
95 
CheckDataWithQuery(QueryObject query,std::vector<DataItem> & dataItems,const DeviceInfo & deviceInfo)96 int SQLiteSingleVerStorageExecutor::CheckDataWithQuery(QueryObject query, std::vector<DataItem> &dataItems,
97     const DeviceInfo &deviceInfo)
98 {
99     int errCode = E_OK;
100     if (query.Empty()) {
101         LOGD("Query is empty, skip check.");
102         return E_OK;
103     }
104     SqliteQueryHelper helper = query.GetQueryHelper(errCode);
105     if (errCode != E_OK) {
106         LOGE("Get query helper failed [%d]!", errCode);
107         return errCode;
108     }
109     std::string sql;
110     errCode = helper.GetSyncDataCheckSql(sql);
111     if (errCode != E_OK) {
112         LOGE("Get sync data check sql failed");
113         return errCode;
114     }
115     sqlite3_stmt *stmt = nullptr;
116     errCode = SQLiteUtils::GetStatement(dbHandle_, sql, stmt);
117     if (errCode != E_OK) {
118         LOGE("Get statement fail. %d", errCode);
119         return -E_INVALID_QUERY_FORMAT;
120     }
121     errCode = CheckMissQueryDataItems(stmt, helper, deviceInfo, dataItems);
122     if (errCode != E_OK) {
123         LOGE("check data with query failed. %d", errCode);
124     }
125     SQLiteUtils::ResetStatement(stmt, true, errCode);
126     return CheckCorruptedStatus(errCode);
127 }
128 
129 namespace {
FormatSubscribeTriggerSql(const std::string & subscribeId,const std::string & subscribeCondition,TriggerModeEnum mode)130 std::string FormatSubscribeTriggerSql(const std::string &subscribeId, const std::string &subscribeCondition,
131     TriggerModeEnum mode)
132 {
133     std::string triggerModeString = GetTriggerModeString(mode);
134     std::string accessString = ((mode == TriggerModeEnum::DELETE) ?
135         DBConstant::TRIGGER_REFERENCES_OLD : DBConstant::TRIGGER_REFERENCES_NEW);
136     std::string keyStr = DBConstant::SUBSCRIBE_QUERY_PREFIX + DBCommon::TransferHashString(subscribeId);
137     Key key {keyStr.begin(), keyStr.end()};
138     std::string hexKeyStr = DBCommon::VectorToHexString(key);
139     std::string triggerName = DBConstant::SUBSCRIBE_QUERY_PREFIX + subscribeId + "_ON_" + triggerModeString;
140     return "CREATE TRIGGER IF NOT EXISTS " + triggerName + " AFTER " + triggerModeString + " \n"
141         "ON sync_data\n"
142         "WHEN ((NEW.flag&0x02=0x02) AND (" + subscribeCondition + "))\n" // filter locally changed data
143         "BEGIN\n"
144         "    SELECT " + DBConstant::UPDATE_META_FUNC + "(x'" + hexKeyStr + "', NEW.TIMESTAMP);\n"
145         "END;";
146 }
147 }
148 
AddSubscribeTrigger(QueryObject & query,const std::string & subscribeId)149 int SQLiteSingleVerStorageExecutor::AddSubscribeTrigger(QueryObject &query, const std::string &subscribeId)
150 {
151     if (executorState_ == ExecutorState::CACHEDB || executorState_ == ExecutorState::CACHE_ATTACH_MAIN) {
152         LOGE("Not support add subscribe in cache db.");
153         return -E_EKEYREVOKED;
154     }
155     int errCode = E_OK;
156     SqliteQueryHelper helper = query.GetQueryHelper(errCode);
157     if (errCode != E_OK) {
158         LOGE("Get query helper failed. %d", errCode);
159         return errCode;
160     }
161     // check if sqlite function is registered or not
162     sqlite3_stmt *stmt = nullptr;
163     errCode = SQLiteUtils::GetStatement(dbHandle_, "SELECT " + DBConstant::UPDATE_META_FUNC + "('K', 0);", stmt);
164     if (errCode != E_OK) {
165         LOGE("sqlite function %s has not been created.", DBConstant::UPDATE_META_FUNC.c_str());
166         return -E_NOT_SUPPORT;
167     }
168     SQLiteUtils::ResetStatement(stmt, true, errCode);
169 
170     // Delete data API is actually an update operation, there is no need for DELETE trigger
171     for (auto mode : {TriggerModeEnum::INSERT, TriggerModeEnum::UPDATE}) {
172         std::string subscribeCondition;
173         errCode = helper.GetSubscribeSql(subscribeId, mode, subscribeCondition);
174         if (errCode != E_OK) {
175             LOGE("Get subscribe trigger create sql failed. mode: %d, errCode: %d", static_cast<int>(mode),
176                 errCode);
177             return errCode;
178         }
179         std::string sql = FormatSubscribeTriggerSql(subscribeId, subscribeCondition, mode);
180         errCode = SQLiteUtils::ExecuteRawSQL(dbHandle_, sql);
181         if (errCode != E_OK) {
182             LOGE("Add subscribe trigger failed. mode: %d, errCode: %d", static_cast<int>(mode), errCode);
183             return errCode;
184         }
185     }
186     return E_OK;
187 }
188 
RemoveSubscribeTrigger(const std::vector<std::string> & subscribeIds)189 int SQLiteSingleVerStorageExecutor::RemoveSubscribeTrigger(const std::vector<std::string> &subscribeIds)
190 {
191     int errCode = E_OK;
192     for (const auto &id : subscribeIds) {
193         for (auto mode : {TriggerModeEnum::INSERT, TriggerModeEnum::UPDATE}) {
194             const std::string trigger = DBConstant::SUBSCRIBE_QUERY_PREFIX + id + "_ON_" + GetTriggerModeString(mode);
195             errCode = SQLiteUtils::DropTriggerByName(dbHandle_, trigger);
196             if (errCode != E_OK) {
197                 LOGE("remove subscribe trigger failed. %d", errCode);
198                 break;
199             }
200         }
201         if (errCode != E_OK) {
202             LOGE("remove subscribe trigger for id %s failed. %d", id.c_str(), errCode);
203             break;
204         }
205     }
206     return errCode;
207 }
208 
RemoveTrigger(const std::vector<std::string> & triggers)209 int SQLiteSingleVerStorageExecutor::RemoveTrigger(const std::vector<std::string> &triggers)
210 {
211     int errCode = E_OK;
212     for (const auto &trigger : triggers) {
213         errCode = SQLiteUtils::DropTriggerByName(dbHandle_, trigger);
214         if (errCode != E_OK) {
215             LOGE("remove trigger failed. %d", errCode);
216             break;
217         }
218     }
219     return errCode;
220 }
221 
RemoveSubscribeTriggerWaterMark(const std::vector<std::string> & subscribeIds)222 int SQLiteSingleVerStorageExecutor::RemoveSubscribeTriggerWaterMark(const std::vector<std::string> &subscribeIds)
223 {
224     sqlite3_stmt *statement = nullptr;
225     const std::string sql = attachMetaMode_ ? REMOVE_ATTACH_META_VALUE_SQL : REMOVE_META_VALUE_SQL;
226     int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, statement);
227     if (errCode != E_OK) {
228         LOGE("Get remove trigger water mark statement failed. %d", errCode);
229         return errCode;
230     }
231     for (const auto &id : subscribeIds) {
232         errCode = SQLiteUtils::BindTextToStatement(statement, 1, DBConstant::SUBSCRIBE_QUERY_PREFIX + id);
233         if (errCode != E_OK) {
234             LOGE("Bind mark key to statement failed. %d", errCode);
235             break;
236         }
237         errCode = SQLiteUtils::StepWithRetry(statement, isMemDb_);
238         if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
239             errCode = E_OK;
240         } else {
241             LOGE("Remove trigger water mark failed. %d", errCode);
242             break;
243         }
244         SQLiteUtils::ResetStatement(statement, false, errCode);
245     }
246     SQLiteUtils::ResetStatement(statement, true, errCode);
247     return errCode;
248 }
249 
GetTriggers(const std::string & namePreFix,std::vector<std::string> & triggerNames)250 int SQLiteSingleVerStorageExecutor::GetTriggers(const std::string &namePreFix, std::vector<std::string> &triggerNames)
251 {
252     sqlite3_stmt *stmt = nullptr;
253     int errCode = SQLiteUtils::GetStatement(dbHandle_, GET_SYNC_DATA_TIRGGER_SQL, stmt);
254     if (errCode != E_OK) {
255         LOGE("Get trigger query statement failed. %d", errCode);
256         return errCode;
257     }
258 
259     errCode = SQLiteUtils::BindTextToStatement(stmt, 1, namePreFix + "%");
260     if (errCode != E_OK) {
261         SQLiteUtils::ResetStatement(stmt, true, errCode);
262         LOGE("Bind trigger name prefix to statement failed. %d", errCode);
263         return errCode;
264     }
265 
266     do {
267         errCode = SQLiteUtils::StepWithRetry(stmt, isMemDb_);
268         if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
269             errCode = E_OK;
270             break;
271         } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
272             std::string name;
273             SQLiteUtils::GetColumnTextValue(stmt, 0, name);
274             triggerNames.emplace_back(name);
275         } else {
276             LOGE("Get trigger by name prefix failed. %d", errCode);
277             break;
278         }
279     } while (true);
280 
281     SQLiteUtils::ResetStatement(stmt, true, errCode);
282     return errCode;
283 }
284 } // namespace DistributedDB
285