• 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     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 " + subscribeCondition + "\n"
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_NOT_SUPPORT;
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", mode, errCode);
176             return errCode;
177         }
178         std::string sql = FormatSubscribeTriggerSql(subscribeId, subscribeCondition, mode);
179         errCode = SQLiteUtils::ExecuteRawSQL(dbHandle_, sql);
180         if (errCode != E_OK) {
181             LOGE("Add subscribe trigger failed. mode: %d, errCode: %d", mode, errCode);
182             return errCode;
183         }
184     }
185     return E_OK;
186 }
187 
RemoveSubscribeTrigger(const std::vector<std::string> & subscribeIds)188 int SQLiteSingleVerStorageExecutor::RemoveSubscribeTrigger(const std::vector<std::string> &subscribeIds)
189 {
190     int errCode = E_OK;
191     for (const auto &id : subscribeIds) {
192         for (auto mode : {TriggerModeEnum::INSERT, TriggerModeEnum::UPDATE}) {
193             const std::string trigger = DBConstant::SUBSCRIBE_QUERY_PREFIX + id + "_ON_" + GetTriggerModeString(mode);
194             errCode = SQLiteUtils::DropTriggerByName(dbHandle_, trigger);
195             if (errCode != E_OK) {
196                 LOGE("remove subscribe trigger failed. %d", errCode);
197                 break;
198             }
199         }
200         if (errCode != E_OK) {
201             LOGE("remove subscribe trigger for id %s failed. %d", id.c_str(), errCode);
202             break;
203         }
204     }
205     return errCode;
206 }
207 
RemoveTrigger(const std::vector<std::string> & triggers)208 int SQLiteSingleVerStorageExecutor::RemoveTrigger(const std::vector<std::string> &triggers)
209 {
210     int errCode = E_OK;
211     for (const auto &trigger : triggers) {
212         errCode = SQLiteUtils::DropTriggerByName(dbHandle_, trigger);
213         if (errCode != E_OK) {
214             LOGE("remove trigger failed. %d", errCode);
215             break;
216         }
217     }
218     return errCode;
219 }
220 
RemoveSubscribeTriggerWaterMark(const std::vector<std::string> & subscribeIds)221 int SQLiteSingleVerStorageExecutor::RemoveSubscribeTriggerWaterMark(const std::vector<std::string> &subscribeIds)
222 {
223     sqlite3_stmt *statement = nullptr;
224     const std::string sql = attachMetaMode_ ? REMOVE_ATTACH_META_VALUE_SQL : REMOVE_META_VALUE_SQL;
225     int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, statement);
226     if (errCode != E_OK) {
227         LOGE("Get remove trigger water mark statement failed. %d", errCode);
228         return errCode;
229     }
230     for (const auto &id : subscribeIds) {
231         errCode = SQLiteUtils::BindTextToStatement(statement, 1, DBConstant::SUBSCRIBE_QUERY_PREFIX + id);
232         if (errCode != E_OK) {
233             LOGE("Bind mark key to statement failed. %d", errCode);
234             break;
235         }
236         errCode = SQLiteUtils::StepWithRetry(statement, isMemDb_);
237         if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
238             errCode = E_OK;
239         } else {
240             LOGE("Remove trigger water mark failed. %d", errCode);
241             break;
242         }
243         SQLiteUtils::ResetStatement(statement, false, errCode);
244     }
245     SQLiteUtils::ResetStatement(statement, true, errCode);
246     return errCode;
247 }
248 
GetTriggers(const std::string & namePreFix,std::vector<std::string> & triggerNames)249 int SQLiteSingleVerStorageExecutor::GetTriggers(const std::string &namePreFix, std::vector<std::string> &triggerNames)
250 {
251     sqlite3_stmt *stmt = nullptr;
252     int errCode = SQLiteUtils::GetStatement(dbHandle_, GET_SYNC_DATA_TIRGGER_SQL, stmt);
253     if (errCode != E_OK) {
254         LOGE("Get trigger query statement failed. %d", errCode);
255         return errCode;
256     }
257 
258     errCode = SQLiteUtils::BindTextToStatement(stmt, 1, namePreFix + "%");
259     if (errCode != E_OK) {
260         SQLiteUtils::ResetStatement(stmt, true, errCode);
261         LOGE("Bind trigger name prefix to statement failed. %d", errCode);
262         return errCode;
263     }
264 
265     do {
266         errCode = SQLiteUtils::StepWithRetry(stmt, isMemDb_);
267         if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
268             errCode = E_OK;
269             break;
270         } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
271             std::string name;
272             SQLiteUtils::GetColumnTextValue(stmt, 0, name);
273             triggerNames.emplace_back(name);
274         } else {
275             LOGE("Get trigger by name prefix failed. %d", errCode);
276             break;
277         }
278     } while (true);
279 
280     SQLiteUtils::ResetStatement(stmt, true, errCode);
281     return errCode;
282 }
283 } // namespace DistributedDB
284