1 /*
2 * Copyright (c) 2025 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_relational_utils.h"
17 #include "db_common.h"
18 #include "time_helper.h"
19
20 namespace DistributedDB {
CreateRelationalMetaTable(sqlite3 * db)21 int SQLiteRelationalUtils::CreateRelationalMetaTable(sqlite3 *db)
22 {
23 std::string sql =
24 "CREATE TABLE IF NOT EXISTS " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata(" \
25 "key BLOB PRIMARY KEY NOT NULL," \
26 "value BLOB);";
27 int errCode = SQLiteUtils::ExecuteRawSQL(db, sql);
28 if (errCode != E_OK) {
29 LOGE("[SQLite] execute create table sql failed, err=%d", errCode);
30 }
31 return errCode;
32 }
33
GetKvData(sqlite3 * db,bool isMemory,const Key & key,Value & value)34 int SQLiteRelationalUtils::GetKvData(sqlite3 *db, bool isMemory, const Key &key, Value &value)
35 {
36 static const std::string SELECT_META_VALUE_SQL = "SELECT value FROM " + std::string(DBConstant::RELATIONAL_PREFIX) +
37 "metadata WHERE key=?;";
38 sqlite3_stmt *statement = nullptr;
39 int errCode = SQLiteUtils::GetStatement(db, SELECT_META_VALUE_SQL, statement);
40 if (errCode != E_OK) {
41 return SQLiteUtils::ProcessStatementErrCode(statement, true, errCode);
42 }
43
44 errCode = SQLiteUtils::BindBlobToStatement(statement, 1, key, false); // first arg.
45 if (errCode != E_OK) {
46 return SQLiteUtils::ProcessStatementErrCode(statement, true, errCode);
47 }
48
49 errCode = SQLiteUtils::StepWithRetry(statement, isMemory);
50 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
51 errCode = -E_NOT_FOUND;
52 return SQLiteUtils::ProcessStatementErrCode(statement, true, errCode);
53 } else if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
54 return SQLiteUtils::ProcessStatementErrCode(statement, true, errCode);
55 }
56
57 errCode = SQLiteUtils::GetColumnBlobValue(statement, 0, value); // only one result.
58 return SQLiteUtils::ProcessStatementErrCode(statement, true, errCode);
59 }
60
PutKvData(sqlite3 * db,bool isMemory,const Key & key,const Value & value)61 int SQLiteRelationalUtils::PutKvData(sqlite3 *db, bool isMemory, const Key &key, const Value &value)
62 {
63 static const std::string INSERT_META_SQL = "INSERT OR REPLACE INTO " + std::string(DBConstant::RELATIONAL_PREFIX) +
64 "metadata VALUES(?,?);";
65 sqlite3_stmt *statement = nullptr;
66 int errCode = SQLiteUtils::GetStatement(db, INSERT_META_SQL, statement);
67 if (errCode != E_OK) {
68 return errCode;
69 }
70
71 errCode = SQLiteUtils::BindBlobToStatement(statement, 1, key, false); // 1 means key index
72 if (errCode != E_OK) {
73 LOGE("[SingleVerExe][BindPutKv]Bind key error:%d", errCode);
74 return SQLiteUtils::ProcessStatementErrCode(statement, true, errCode);
75 }
76
77 errCode = SQLiteUtils::BindBlobToStatement(statement, 2, value, true); // 2 means value index
78 if (errCode != E_OK) {
79 LOGE("[SingleVerExe][BindPutKv]Bind value error:%d", errCode);
80 return SQLiteUtils::ProcessStatementErrCode(statement, true, errCode);
81 }
82 errCode = SQLiteUtils::StepWithRetry(statement, isMemory);
83 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
84 errCode = E_OK;
85 }
86 return SQLiteUtils::ProcessStatementErrCode(statement, true, errCode);
87 }
88
InitCursorToMeta(sqlite3 * db,bool isMemory,const std::string & tableName)89 int SQLiteRelationalUtils::InitCursorToMeta(sqlite3 *db, bool isMemory, const std::string &tableName)
90 {
91 Value key;
92 Value cursor;
93 DBCommon::StringToVector(DBCommon::GetCursorKey(tableName), key);
94 int errCode = GetKvData(db, isMemory, key, cursor);
95 if (errCode == -E_NOT_FOUND) {
96 DBCommon::StringToVector(std::string("0"), cursor);
97 errCode = PutKvData(db, isMemory, key, cursor);
98 if (errCode != E_OK) {
99 LOGE("Init cursor to meta table failed. %d", errCode);
100 }
101 return errCode;
102 }
103 if (errCode != E_OK) {
104 LOGE("Get cursor from meta table failed. %d", errCode);
105 }
106 return errCode;
107 }
108
InitKnowledgeTableTypeToMeta(sqlite3 * db,bool isMemory,const std::string & tableName)109 int SQLiteRelationalUtils::InitKnowledgeTableTypeToMeta(sqlite3 *db, bool isMemory, const std::string &tableName)
110 {
111 std::string tableTypeKey = "sync_table_type_" + tableName;
112 Value key;
113 DBCommon::StringToVector(tableTypeKey, key);
114 Value value;
115 int errCode = GetKvData(db, isMemory, key, value);
116 if (errCode == -E_NOT_FOUND) {
117 DBCommon::StringToVector(DBConstant::KNOWLEDGE_TABLE_TYPE, value);
118 errCode = PutKvData(db, isMemory, key, value);
119 if (errCode != E_OK) {
120 LOGE("Init table type to meta table failed. %d", errCode);
121 return errCode;
122 }
123 }
124 if (errCode != E_OK) {
125 LOGE("Get table type from meta table failed. %d", errCode);
126 }
127 return errCode;
128 }
129
SetLogTriggerStatus(sqlite3 * db,bool status)130 int SQLiteRelationalUtils::SetLogTriggerStatus(sqlite3 *db, bool status)
131 {
132 const std::string key = "log_trigger_switch";
133 std::string val = status ? "true" : "false";
134 std::string sql = "INSERT OR REPLACE INTO " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata" +
135 " VALUES ('" + key + "', '" + val + "')";
136 int errCode = SQLiteUtils::ExecuteRawSQL(db, sql);
137 if (errCode != E_OK) {
138 LOGE("Set log trigger to %s failed. errCode=%d", val.c_str(), errCode);
139 }
140 return errCode;
141 }
142
GeneLogInfoForExistedData(const std::string & identity,const TableInfo & tableInfo,std::unique_ptr<SqliteLogTableManager> & logMgrPtr,GenLogParam & param)143 int SQLiteRelationalUtils::GeneLogInfoForExistedData(const std::string &identity, const TableInfo &tableInfo,
144 std::unique_ptr<SqliteLogTableManager> &logMgrPtr, GenLogParam ¶m)
145 {
146 std::string tableName = tableInfo.GetTableName();
147 std::string timeStr;
148 int errCode = GeneTimeStrForLog(tableInfo, param, timeStr);
149 if (errCode != E_OK) {
150 return errCode;
151 }
152 errCode = SetLogTriggerStatus(param.db, false);
153 if (errCode != E_OK) {
154 return errCode;
155 }
156 std::string logTable = DBConstant::RELATIONAL_PREFIX + tableName + "_log";
157 std::string rowid = std::string(DBConstant::SQLITE_INNER_ROWID);
158 uint32_t flagVal = static_cast<uint32_t>(LogInfoFlag::FLAG_LOCAL);
159 if (tableInfo.GetTableSyncType() == TableSyncType::CLOUD_COOPERATION) {
160 flagVal = flagVal | static_cast<uint32_t>(LogInfoFlag::FLAG_DEVICE_CLOUD_INCONSISTENCY);
161 }
162 std::string flag = std::to_string(flagVal);
163 TrackerTable trackerTable = tableInfo.GetTrackerTable();
164 trackerTable.SetTableName(tableName);
165 const std::string prefix = "a.";
166 std::string calPrimaryKeyHash = logMgrPtr->CalcPrimaryKeyHash(prefix, tableInfo, identity);
167 std::string sql = "INSERT OR REPLACE INTO " + logTable + " SELECT " + rowid + ", '', '', " + timeStr + " + " +
168 rowid + ", " + timeStr + " + " + rowid + ", " + flag + ", " + calPrimaryKeyHash + ", '', ";
169 sql += GetExtendValue(tableInfo.GetTrackerTable());
170 sql += ", 0, '', '', 0 FROM '" + tableName + "' AS a ";
171 if (param.isTrackerTable) {
172 sql += " WHERE 1 = 1;";
173 } else {
174 sql += "WHERE NOT EXISTS (SELECT 1 FROM " + logTable + " WHERE data_key = a._rowid_);";
175 }
176 errCode = trackerTable.ReBuildTempTrigger(param.db, TriggerMode::TriggerModeEnum::INSERT, [db = param.db, &sql]() {
177 int ret = SQLiteUtils::ExecuteRawSQL(db, sql);
178 if (ret != E_OK) {
179 LOGE("Failed to initialize cloud type log data.%d", ret);
180 }
181 return ret;
182 });
183 return errCode;
184 }
185
GetExistedDataTimeOffset(sqlite3 * db,const std::string & tableName,bool isMem,int64_t & timeOffset)186 int SQLiteRelationalUtils::GetExistedDataTimeOffset(sqlite3 *db, const std::string &tableName, bool isMem,
187 int64_t &timeOffset)
188 {
189 std::string sql = "SELECT get_sys_time(0) - max(" + std::string(DBConstant::SQLITE_INNER_ROWID) + ") - 1 FROM '" +
190 tableName + "';";
191 sqlite3_stmt *stmt = nullptr;
192 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
193 if (errCode != E_OK) {
194 return errCode;
195 }
196 errCode = SQLiteUtils::StepWithRetry(stmt, isMem);
197 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
198 timeOffset = static_cast<int64_t>(sqlite3_column_int64(stmt, 0));
199 errCode = E_OK;
200 }
201 int ret = E_OK;
202 SQLiteUtils::ResetStatement(stmt, true, ret);
203 return errCode != E_OK ? errCode : ret;
204 }
205
GetExtendValue(const TrackerTable & trackerTable)206 std::string SQLiteRelationalUtils::GetExtendValue(const TrackerTable &trackerTable)
207 {
208 std::string extendValue;
209 const std::set<std::string> &extendNames = trackerTable.GetExtendNames();
210 if (!extendNames.empty()) {
211 extendValue += "json_object(";
212 for (const auto &extendName : extendNames) {
213 extendValue += "'" + extendName + "'," + extendName + ",";
214 }
215 extendValue.pop_back();
216 extendValue += ")";
217 } else {
218 extendValue = "''";
219 }
220 return extendValue;
221 }
222
CleanTrackerData(sqlite3 * db,const std::string & tableName,int64_t cursor,bool isOnlyTrackTable)223 int SQLiteRelationalUtils::CleanTrackerData(sqlite3 *db, const std::string &tableName, int64_t cursor,
224 bool isOnlyTrackTable)
225 {
226 std::string sql;
227 if (isOnlyTrackTable) {
228 sql = "DELETE FROM " + std::string(DBConstant::RELATIONAL_PREFIX) + tableName + "_log";
229 } else {
230 sql = "UPDATE " + std::string(DBConstant::RELATIONAL_PREFIX) + tableName + "_log SET extend_field = NULL";
231 }
232 sql += " where data_key = -1 and cursor <= ?;";
233 sqlite3_stmt *statement = nullptr;
234 int errCode = SQLiteUtils::GetStatement(db, sql, statement);
235 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
236 LOGE("get clean tracker data stmt failed %d.", errCode);
237 return errCode;
238 }
239 errCode = SQLiteUtils::BindInt64ToStatement(statement, 1, cursor);
240 int ret = E_OK;
241 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
242 LOGE("bind clean tracker data stmt failed %d.", errCode);
243 SQLiteUtils::ResetStatement(statement, true, ret);
244 return errCode;
245 }
246 errCode = SQLiteUtils::StepWithRetry(statement);
247 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { // LCOV_EXCL_BR_LINE
248 errCode = E_OK;
249 } else {
250 LOGE("clean tracker step failed: %d.", errCode);
251 }
252 SQLiteUtils::ResetStatement(statement, true, ret);
253 return errCode == E_OK ? ret : errCode;
254 }
255
256
AnalysisTrackerTable(sqlite3 * db,const TrackerTable & trackerTable,TableInfo & tableInfo)257 int SQLiteRelationalUtils::AnalysisTrackerTable(sqlite3 *db, const TrackerTable &trackerTable, TableInfo &tableInfo)
258 {
259 int errCode = SQLiteUtils::AnalysisSchema(db, trackerTable.GetTableName(), tableInfo, true);
260 if (errCode != E_OK) {
261 LOGE("analysis table schema failed %d.", errCode);
262 return errCode;
263 }
264 tableInfo.SetTrackerTable(trackerTable);
265 errCode = tableInfo.CheckTrackerTable();
266 if (errCode != E_OK) {
267 LOGE("check tracker table schema failed %d.", errCode);
268 }
269 return errCode;
270 }
271
GetMetaLocalTimeOffset(sqlite3 * db,int64_t & timeOffset)272 int SQLiteRelationalUtils::GetMetaLocalTimeOffset(sqlite3 *db, int64_t &timeOffset)
273 {
274 std::string sql = "SELECT value FROM " + DBCommon::GetMetaTableName() + " WHERE key=x'" +
275 DBCommon::TransferStringToHex(std::string(DBConstant::LOCALTIME_OFFSET_KEY)) + "';";
276 sqlite3_stmt *stmt = nullptr;
277 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
278 if (errCode != E_OK) {
279 return errCode;
280 }
281 int ret = E_OK;
282 errCode = SQLiteUtils::StepWithRetry(stmt);
283 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
284 timeOffset = static_cast<int64_t>(sqlite3_column_int64(stmt, 0));
285 if (timeOffset < 0) {
286 LOGE("[SQLiteRDBUtils] TimeOffset %" PRId64 "is invalid.", timeOffset);
287 SQLiteUtils::ResetStatement(stmt, true, ret);
288 return -E_INTERNAL_ERROR;
289 }
290 errCode = E_OK;
291 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
292 timeOffset = 0;
293 errCode = E_OK;
294 }
295 SQLiteUtils::ResetStatement(stmt, true, ret);
296 return errCode != E_OK ? errCode : ret;
297 }
298
GetCurrentVirtualTime(sqlite3 * db)299 std::pair<int, std::string> SQLiteRelationalUtils::GetCurrentVirtualTime(sqlite3 *db)
300 {
301 int64_t localTimeOffset = 0;
302 std::pair<int, std::string> res;
303 auto &[errCode, time] = res;
304 errCode = GetMetaLocalTimeOffset(db, localTimeOffset);
305 if (errCode != E_OK) {
306 LOGE("[SQLiteRDBUtils] Failed to get local timeOffset.%d", errCode);
307 return res;
308 }
309 Timestamp currentSysTime = TimeHelper::GetSysCurrentTime();
310 Timestamp currentLocalTime = currentSysTime + static_cast<uint64_t>(localTimeOffset);
311 time = std::to_string(currentLocalTime);
312 return res;
313 }
314
GeneTimeStrForLog(const TableInfo & tableInfo,GenLogParam & param,std::string & timeStr)315 int SQLiteRelationalUtils::GeneTimeStrForLog(const TableInfo &tableInfo, GenLogParam ¶m, std::string &timeStr)
316 {
317 if (tableInfo.GetTableSyncType() == TableSyncType::DEVICE_COOPERATION) {
318 auto [errCode, time] = GetCurrentVirtualTime(param.db);
319 if (errCode != E_OK) {
320 LOGE("Failed to get current virtual time.%d", errCode);
321 return errCode;
322 }
323 timeStr = time;
324 } else {
325 int64_t timeOffset = 0;
326 std::string tableName = tableInfo.GetTableName();
327 int errCode = GetExistedDataTimeOffset(param.db, tableName, param.isMemory, timeOffset);
328 if (errCode != E_OK) {
329 return errCode;
330 }
331 timeStr = std::to_string(timeOffset);
332 }
333 return E_OK;
334 }
335 } // namespace DistributedDB