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