From c6fe7ffa27bf1b907c5843579e3e2f2d45b1f913 Mon Sep 17 00:00:00 2001 From: suyuchen Date: Fri, 7 Nov 2025 19:02:48 +0800 Subject: [PATCH] keep flag when updated content is identical Signed-off-by: suyuchen --- .../libs/distributeddb/distributeddb.gni | 2 + .../src/relational/knowledge_source_utils.cpp | 164 ++++++++++++++- .../src/relational/knowledge_source_utils.h | 9 + .../knowledge_log_table_manager.cpp | 69 +++++++ .../relational/knowledge_log_table_manager.h | 35 ++++ ...istributeddb_rdb_knowledge_client_test.cpp | 191 ++++++++++++++++++ 6 files changed, 465 insertions(+), 5 deletions(-) create mode 100644 frameworks/libs/distributeddb/storage/src/sqlite/relational/knowledge_log_table_manager.cpp create mode 100644 frameworks/libs/distributeddb/storage/src/sqlite/relational/knowledge_log_table_manager.h diff --git a/frameworks/libs/distributeddb/distributeddb.gni b/frameworks/libs/distributeddb/distributeddb.gni index d319fda6a7c..b23a39e063c 100755 --- a/frameworks/libs/distributeddb/distributeddb.gni +++ b/frameworks/libs/distributeddb/distributeddb.gni @@ -166,6 +166,7 @@ distributeddb_src = [ "${distributeddb_path}/storage/src/sqlite/relational/cloud_sync_log_table_manager.cpp", "${distributeddb_path}/storage/src/sqlite/relational/collaboration_log_table_manager.cpp", "${distributeddb_path}/storage/src/sqlite/relational/device_tracker_log_table_manager.cpp", + "${distributeddb_path}/storage/src/sqlite/relational/knowledge_log_table_manager.cpp", "${distributeddb_path}/storage/src/sqlite/relational/log_table_manager_factory.cpp", "${distributeddb_path}/storage/src/sqlite/relational/relational_remote_query_continue_token.cpp", "${distributeddb_path}/storage/src/sqlite/relational/simple_tracker_log_table_manager.cpp", @@ -327,6 +328,7 @@ distributeddb_base_src = [ "${distributeddb_path}/interfaces/src/kv_store_errno.cpp", "${distributeddb_path}/storage/src/cloud/cloud_storage_utils_client.cpp", "${distributeddb_path}/storage/src/sqlite/relational/cloud_sync_log_table_manager.cpp", + "${distributeddb_path}/storage/src/sqlite/relational/knowledge_log_table_manager.cpp", "${distributeddb_path}/storage/src/sqlite/relational/simple_tracker_log_table_manager.cpp", "${distributeddb_path}/storage/src/sqlite/relational/split_device_log_table_manager.cpp", "${distributeddb_path}/storage/src/sqlite/relational/sqlite_relational_utils_client.cpp", diff --git a/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.cpp b/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.cpp index 87bb5320ee2..040a78c16c5 100644 --- a/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.cpp +++ b/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.cpp @@ -14,10 +14,11 @@ */ #include "knowledge_source_utils.h" +#include "cloud/cloud_storage_utils.h" #include "db_common.h" #include "db_errno.h" #include "res_finalizer.h" -#include "simple_tracker_log_table_manager.h" +#include "knowledge_log_table_manager.h" #include "sqlite_relational_utils.h" #include "sqlite_utils.h" @@ -51,6 +52,7 @@ TrackerSchema GetTrackerSchema(const KnowledgeSourceSchema &schema) } constexpr const char *PROCESS_SEQ_KEY = "processSequence"; +constexpr const char *KNOWLEDGE_CURSOR_PREFIX = "knowledge_cursor_"; int KnowledgeSourceUtils::CheckProcessSequence(sqlite3 *db, const std::string &tableName, const std::string &columnName) @@ -192,9 +194,7 @@ int KnowledgeSourceUtils::SetKnowledgeSourceSchemaInner(sqlite3 *db, const Knowl if (!isChanged) { LOGI("Knowledge schema is no change, table %s len %zu", DBCommon::StringMiddleMasking(schema.tableName).c_str(), schema.tableName.size()); - std::unique_ptr tableManager = std::make_unique(); - tableManager->CheckAndCreateTrigger(db, tableInfo, ""); - return E_OK; + return UpdateFlagAndTriggerIfNeeded(db, tableInfo); } errCode = InitLogTable(db, schema, tableInfo); if (errCode != E_OK) { @@ -204,6 +204,160 @@ int KnowledgeSourceUtils::SetKnowledgeSourceSchemaInner(sqlite3 *db, const Knowl return SaveKnowledgeSourceSchema(db, knowledgeSchema); } +int KnowledgeSourceUtils::UpdateFlagAndTriggerIfNeeded(sqlite3 *db, const TableInfo &tableInfo) +{ + std::string updateTriggerName = "naturalbase_rdb_" + tableInfo.GetTableName() + "_ON_UPDATE"; + + bool needUpdate = false; + int errCode = CheckUpdateTriggerVersion(db, updateTriggerName, tableInfo.GetTableName(), needUpdate); + if (errCode != E_OK) { + LOGE("Check knowledge table trigger err %d", errCode); + return errCode; + } + + std::unique_ptr tableManager = std::make_unique(); + if (!needUpdate) { + tableManager->CheckAndCreateTrigger(db, tableInfo, ""); + return E_OK; + } + + LOGI("Knowledge table trigger needs update"); + errCode = UpdateKnowledgeFlag(db, tableInfo); + if (errCode != E_OK) { + LOGE("Update knowledge flag err %d", errCode); + return errCode; + } + + errCode = tableManager->AddRelationalLogTableTrigger(db, tableInfo, ""); + if (errCode != E_OK) { + LOGE("Update existing trigger err %d", errCode); + } + return errCode; +} + +int KnowledgeSourceUtils::CheckUpdateTriggerVersion(sqlite3 *db, const std::string &triggerName, + const std::string &tableName, bool &needUpdate) +{ + std::string checkSql = "select sql from sqlite_master where type = 'trigger' and tbl_name = '" + + tableName + "' and name = '" + triggerName + "';"; + + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, checkSql, stmt); + if (errCode != E_OK) { + LOGE("[CheckUpdateTriggerVersion] Get statement err:%d", errCode); + return errCode; + } + + ResFinalizer finalizer([stmt]() { + sqlite3_stmt *statement = stmt; + int ret = E_OK; + SQLiteUtils::ResetStatement(statement, true, ret); + if (ret != E_OK) { + LOGW("Reset stmt failed when check trigger version %d", ret); + } + }); + + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + return E_OK; + } + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + LOGE("Get trigger err: %d", errCode); + return errCode; + } + + std::string trigger; + errCode = SQLiteUtils::GetColumnTextValue(stmt, 0, trigger); + if (errCode != E_OK) { + LOGE("Get trigger statement err: %d", errCode); + return errCode; + } + + std::string newPattern = "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName); + size_t pos = trigger.find(newPattern); + // trigger is new version if pattern matches + needUpdate = (pos == std::string::npos); + return E_OK; +} + +int KnowledgeSourceUtils::UpdateKnowledgeFlag(sqlite3 *db, const TableInfo &tableInfo) +{ + int64_t cursor = 0; + int errCode = GetKnowledgeCursor(db, tableInfo, cursor); + if (errCode != E_OK) { + LOGE("Get knowledge cursor err:%d", errCode); + return errCode; + } + + std::string logTblName = DBConstant::RELATIONAL_PREFIX + tableInfo.GetTableName() + "_log"; + uint32_t newFlag = static_cast(LogInfoFlag::FLAG_KNOWLEDGE_INVERTED_WRITE) | + static_cast(LogInfoFlag::FLAG_KNOWLEDGE_VECTOR_WRITE); + std::string sql = "UPDATE " + logTblName + " SET flag = flag | " + std::to_string(newFlag) + " WHERE cursor <= ?;"; + + sqlite3_stmt *stmt = nullptr; + errCode = SQLiteUtils::GetStatement(db, sql, stmt); + if (errCode != E_OK) { + LOGE("[UpdateKnowledgeFlag] Get statement err:%d", errCode); + return errCode; + } + + ResFinalizer finalizer([stmt]() { + sqlite3_stmt *statement = stmt; + int ret = E_OK; + SQLiteUtils::ResetStatement(statement, true, ret); + if (ret != E_OK) { + LOGW("Reset stmt failed when update knowledge flag %d", ret); + } + }); + + errCode = SQLiteUtils::BindInt64ToStatement(stmt, 1, cursor); + if (errCode != E_OK) { + LOGE("UpdateKnowledgeFlag bind arg err:%d", errCode); + return errCode; + } + + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + LOGE("Execute update flag statement err:%d", errCode); + return errCode; + } + return E_OK; +} + +int KnowledgeSourceUtils::GetKnowledgeCursor(sqlite3 *db, const TableInfo &tableInfo, int64_t &cursor) +{ + std::string cursorKey = std::string(KNOWLEDGE_CURSOR_PREFIX) + tableInfo.GetTableName(); + std::string cursorSql = "SELECT value FROM naturalbase_rdb_aux_metadata WHERE key = '" + cursorKey + "';"; + + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, cursorSql, stmt); + if (errCode != E_OK) { + LOGE("[GetKnowledgeCursor] Get statement err:%d", errCode); + return errCode; + } + + ResFinalizer finalizer([stmt]() { + sqlite3_stmt *statement = stmt; + int ret = E_OK; + SQLiteUtils::ResetStatement(statement, true, ret); + if (ret != E_OK) { + LOGW("Reset stmt failed when get knowledge cursor %d", ret); + } + }); + + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + LOGI("Not found knowledge cursor"); + return E_OK; + } + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + LOGE("Get knowledge cursor err:%d", errCode); + return errCode; + } + cursor = sqlite3_column_int64(stmt, 0); + return E_OK; +} + int KnowledgeSourceUtils::RemoveKnowledgeTableSchema(sqlite3 *db, const std::string &tableName) { int errCode = E_OK; @@ -328,7 +482,7 @@ bool KnowledgeSourceUtils::IsSchemaChange(const RelationalSchemaObject &dbSchema int KnowledgeSourceUtils::InitLogTable(sqlite3 *db, const KnowledgeSourceSchema &schema, const TableInfo &tableInfo) { - std::unique_ptr tableManager = std::make_unique(); + std::unique_ptr tableManager = std::make_unique(); auto errCode = tableManager->CreateRelationalLogTable(db, tableInfo); if (errCode != E_OK) { return errCode; diff --git a/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.h b/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.h index 34e2e24a306..b27d387ac4f 100644 --- a/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.h +++ b/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.h @@ -57,6 +57,15 @@ protected: static bool IsSchemaChange(const RelationalSchemaObject &dbSchema, const KnowledgeSourceSchema &schema); static int InitLogTable(sqlite3 *db, const KnowledgeSourceSchema &schema, const TableInfo &tableInfo); + + static int UpdateFlagAndTriggerIfNeeded(sqlite3 *db, const TableInfo &table); + + static int CheckUpdateTriggerVersion(sqlite3 *db, const std::string &triggerName, const std::string &tableName, + bool &needUpdate); + + static int GetKnowledgeCursor(sqlite3 *db, const TableInfo &tableInfo, int64_t &cursor); + + static int UpdateKnowledgeFlag(sqlite3 *db, const TableInfo &tableInfo); }; } diff --git a/frameworks/libs/distributeddb/storage/src/sqlite/relational/knowledge_log_table_manager.cpp b/frameworks/libs/distributeddb/storage/src/sqlite/relational/knowledge_log_table_manager.cpp new file mode 100644 index 00000000000..174f2bd381c --- /dev/null +++ b/frameworks/libs/distributeddb/storage/src/sqlite/relational/knowledge_log_table_manager.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "knowledge_log_table_manager.h" + +#include "cloud/cloud_storage_utils.h" +#include "res_finalizer.h" + +namespace DistributedDB { + +std::string KnowledgeLogTableManager::GetUpdateTrigger(const TableInfo &table, const std::string &identity) +{ + (void)identity; + std::string logTblName = GetLogTableName(table); + std::string tableName = table.GetTableName(); + std::string updateTrigger = "CREATE TRIGGER IF NOT EXISTS "; + updateTrigger += "naturalbase_rdb_" + tableName + "_ON_UPDATE AFTER UPDATE \n"; + updateTrigger += "ON '" + tableName + "'\n"; + updateTrigger += " FOR EACH ROW "; + updateTrigger += "BEGIN\n"; + updateTrigger += CloudStorageUtils::GetCursorIncSql(tableName); + updateTrigger.pop_back(); + updateTrigger += " AND " + table.GetTrackerTable().GetDiffTrackerValSql() + ";"; + updateTrigger += "\t UPDATE " + logTblName; + updateTrigger += " SET timestamp=get_raw_sys_time(), device='', flag=0x02"; + updateTrigger += ", cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName); + updateTrigger += table.GetTrackerTable().GetExtendAssignValSql(); + updateTrigger += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID); + updateTrigger += GetDiffIncSql(table) + ";\n"; + updateTrigger += "SELECT client_observer('" + tableName + "', OLD." + + std::string(DBConstant::SQLITE_INNER_ROWID); + updateTrigger += ", 1, "; + updateTrigger += table.GetTrackerTable().GetDiffTrackerValSql(); + updateTrigger += ");"; + updateTrigger += "END;"; + return updateTrigger; +} + +std::string KnowledgeLogTableManager::GetDiffIncSql(const TableInfo &tableInfo) +{ + const auto &table = tableInfo.GetTrackerTable(); + if (table.IsEmpty()) { + return ""; + } + std::string sql = " AND ("; + size_t index = 0; + for (const auto &colName: table.GetTrackerColNames()) { + sql += "(NEW." + colName + " IS NOT OLD." + colName + ")"; + if (index < table.GetTrackerColNames().size() - 1) { + sql += " OR "; + } + index++; + } + sql += ") "; + return sql; +} +} \ No newline at end of file diff --git a/frameworks/libs/distributeddb/storage/src/sqlite/relational/knowledge_log_table_manager.h b/frameworks/libs/distributeddb/storage/src/sqlite/relational/knowledge_log_table_manager.h new file mode 100644 index 00000000000..8c2c7d31684 --- /dev/null +++ b/frameworks/libs/distributeddb/storage/src/sqlite/relational/knowledge_log_table_manager.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KNOWLEDGE_LOG_TABLE_MANAGER_H +#define KNOWLEDGE_LOG_TABLE_MANAGER_H + +#include "simple_tracker_log_table_manager.h" + +namespace DistributedDB { +class KnowledgeLogTableManager : public SimpleTrackerLogTableManager { +public: + KnowledgeLogTableManager() = default; + ~KnowledgeLogTableManager() override = default; + +private: + // inherit insert and delete trigger from tracker table, only update trigger is different + std::string GetUpdateTrigger(const TableInfo &table, const std::string &identity) override; + + std::string GetDiffIncSql(const TableInfo &tableInfo); +}; +} // DistributedDB + +#endif // KNOWLEDGE_LOG_TABLE_MANAGER_H diff --git a/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_knowledge_client_test.cpp b/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_knowledge_client_test.cpp index 49a6e82a475..f2146f71a7b 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_knowledge_client_test.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_knowledge_client_test.cpp @@ -18,6 +18,7 @@ #include "distributeddb_tools_unit_test.h" #include "rdb_data_generator.h" #include "relational_store_client.h" +#include "res_finalizer.h" #include "sqlite_relational_utils.h" #include "table_info.h" @@ -143,6 +144,66 @@ void InsertDBData(const std::string &tableName, int count, sqlite3 *db) } } +void UpdateDBData(sqlite3 *db, const std::string &tableName, int key, bool isChange) +{ + std::string value = isChange ? std::to_string(key + 1) : std::to_string(key); + std::string sql = "UPDATE " + tableName + " SET int_field1 = " + value + ";"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK); +} + +void SetProcessFlag(sqlite3 *db, int key, uint32_t flag) +{ + std::string sql = "UPDATE naturalbase_rdb_aux_KNOWLEDGE_TABLE_log SET flag=flag|" + std::to_string(flag) + + " WHERE data_key=" + std::to_string(key) + ";"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK); +} + +void CheckFlagAndCursor(sqlite3 *db, const std::string &tableName, int key, uint32_t flag, int64_t cursor) +{ + std::string sql = "SELECT flag, cursor FROM naturalbase_rdb_aux_KNOWLEDGE_TABLE_log WHERE data_key=" + + std::to_string(key) + ";"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, sql, stmt); + ASSERT_EQ(errCode, E_OK); + + ResFinalizer finalizer([stmt]() { + sqlite3_stmt *statement = stmt; + int ret = E_OK; + SQLiteUtils::ResetStatement(statement, true, ret); + if (ret != E_OK) { + LOGW("Reset stmt failed when check column type %d", ret); + } + }); + + errCode = SQLiteUtils::StepWithRetry(stmt); + ASSERT_EQ(errCode, SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)); + + int64_t realFlag = sqlite3_column_int64(stmt, 0); + EXPECT_EQ(realFlag, static_cast(flag)); + + int64_t realCursor = sqlite3_column_int64(stmt, 1); + EXPECT_EQ(realCursor, cursor); +} + +std::string GetOldTriggerSql() +{ + std::string updateTrigger = R"(CREATE TRIGGER IF NOT EXISTS naturalbase_rdb_KNOWLEDGE_TABLE_ON_UPDATE AFTER UPDATE + ON 'KNOWLEDGE_TABLE' + FOR EACH ROW BEGIN + UPDATE naturalbase_rdb_aux_metadata SET value=value+1 WHERE + key=x'6e61747572616c626173655f7264625f6175785f637572736f725f6b6e6f776c656467655f7461626c65' AND CASE WHEN + ((NEW.int_field1 IS NOT OLD.int_field1) OR (NEW.int_field2 IS NOT OLD.int_field2)) THEN 4 ELSE 0 END; + UPDATE naturalbase_rdb_aux_KNOWLEDGE_TABLE_log SET timestamp=get_raw_sys_time(), device='', flag=0x02, + extend_field = json_object('id',NEW.id), cursor = CASE WHEN ((NEW.int_field1 IS NOT OLD.int_field1) OR + (NEW.int_field2 IS NOT OLD.int_field2)) THEN (SELECT value FROM naturalbase_rdb_aux_metadata WHERE + key=x'6e61747572616c626173655f7264625f6175785f637572736f725f6b6e6f776c656467655f7461626c65') + ELSE cursor END WHERE data_key = OLD._rowid_; + SELECT client_observer('KNOWLEDGE_TABLE', OLD._rowid_, 1, CASE WHEN + ((NEW.int_field1 IS NOT OLD.int_field1) OR (NEW.int_field2 IS NOT OLD.int_field2)) + THEN 4 ELSE 0 END);END;)"; + return updateTrigger; +} + /** * @tc.name: SetKnowledge001 * @tc.desc: Test set knowledge schema. @@ -309,4 +370,134 @@ HWTEST_F(DistributedDBRDBKnowledgeClientTest, SetKnowledge004, TestSize.Level0) EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); } + +/** + * @tc.name: SetKnowledge005 + * @tc.desc: Test knowledge table update + * @tc.type: FUNC + * @tc.require: + * @tc.author: suyuchen + */ +HWTEST_F(DistributedDBRDBKnowledgeClientTest, SetKnowledge005, TestSize.Level0) +{ + /** + * @tc.steps: step1. Set knowledge source schema + * @tc.expected: step1. Ok + */ + UtTableSchemaInfo tableInfo = GetTableSchema(KNOWLEDGE_TABLE); + sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX); + EXPECT_NE(db, nullptr); + RDBDataGenerator::InitTableWithSchemaInfo(tableInfo, *db); + KnowledgeSourceSchema schema; + schema.tableName = KNOWLEDGE_TABLE; + schema.extendColNames.insert("id"); + schema.knowledgeColNames.insert("int_field1"); + schema.knowledgeColNames.insert("int_field2"); + EXPECT_EQ(SetKnowledgeSourceSchema(db, schema), OK); + + /** + * @tc.steps: step2. insert data and set flag to processed. + * @tc.expected: step2. Ok + */ + uint32_t flag = static_cast(LogInfoFlag::FLAG_KNOWLEDGE_INVERTED_WRITE); + InsertDBData(schema.tableName, 1, db); + SetProcessFlag(db, 1, flag); + uint32_t expectFlag = static_cast(LogInfoFlag::FLAG_KNOWLEDGE_INVERTED_WRITE) | + static_cast(LogInfoFlag::FLAG_LOCAL); + int64_t expectCursor = 1; + CheckFlagAndCursor(db, schema.tableName, 1, expectFlag, expectCursor); + + /** + * @tc.steps: step3. update data with same content, flag and cursor unchanged + * @tc.expected: step3. Ok + */ + UpdateDBData(db, schema.tableName, 1, false); + CheckFlagAndCursor(db, schema.tableName, 1, expectFlag, expectCursor); + + /** + * @tc.steps: step4. update data with different content, flag and cursor changed + * @tc.expected: step4. Ok + */ + UpdateDBData(db, schema.tableName, 1, true); + expectFlag = static_cast(LogInfoFlag::FLAG_LOCAL); + expectCursor = 2; + CheckFlagAndCursor(db, schema.tableName, 1, expectFlag, expectCursor); + + /** + * @tc.steps: step5. set knowledge schema again when has new trigger. + * @tc.expected: step5. Ok + */ + EXPECT_EQ(SetKnowledgeSourceSchema(db, schema), OK); + + EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); +} + +/** + * @tc.name: SetKnowledge006 + * @tc.desc: Test set knowledge table schema when trigger needs update + * @tc.type: FUNC + * @tc.require: + * @tc.author: suyuchen + */ +HWTEST_F(DistributedDBRDBKnowledgeClientTest, SetKnowledge006, TestSize.Level0) +{ + /** + * @tc.steps: step1. Set knowledge source schema + * @tc.expected: step1. Ok + */ + UtTableSchemaInfo tableInfo = GetTableSchema(KNOWLEDGE_TABLE); + sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX); + EXPECT_NE(db, nullptr); + RDBDataGenerator::InitTableWithSchemaInfo(tableInfo, *db); + KnowledgeSourceSchema schema; + schema.tableName = KNOWLEDGE_TABLE; + schema.extendColNames.insert("id"); + schema.knowledgeColNames.insert("int_field1"); + schema.knowledgeColNames.insert("int_field2"); + EXPECT_EQ(SetKnowledgeSourceSchema(db, schema), OK); + + /** + * @tc.steps: step2. set to old trigger + * @tc.expected: step2. Ok + */ + std::string dropTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + std::string(KNOWLEDGE_TABLE) + "_ON_UPDATE;"; + ASSERT_EQ(RelationalTestUtils::ExecSql(db, dropTrigger), E_OK); + + std::string createOldTrigger = GetOldTriggerSql(); + ASSERT_EQ(RelationalTestUtils::ExecSql(db, createOldTrigger), E_OK); + + /** + * @tc.steps: step3. insert data and update data with same content + * @tc.expected: step3. Ok, flag changed + */ + uint32_t flag = static_cast(LogInfoFlag::FLAG_KNOWLEDGE_INVERTED_WRITE); + InsertDBData(schema.tableName, 1, db); + SetProcessFlag(db, 1, flag); + UpdateDBData(db, schema.tableName, 1, false); + CheckFlagAndCursor(db, schema.tableName, 1, static_cast(LogInfoFlag::FLAG_LOCAL), 1); + + /** + * @tc.steps: step4. Set knowledge cursor and set knowledge source schema again + * @tc.expected: step4. Ok, flag is updated + */ + std::string setCursor = std::string("INSERT OR REPLACE INTO naturalbase_rdb_aux_metadata (key, value) VALUES") + + " ('knowledge_cursor_" + std::string(KNOWLEDGE_TABLE) + "', 1)"; + ASSERT_EQ(RelationalTestUtils::ExecSql(db, setCursor), E_OK); + EXPECT_EQ(SetKnowledgeSourceSchema(db, schema), OK); + + uint32_t expectFlag = static_cast(LogInfoFlag::FLAG_KNOWLEDGE_INVERTED_WRITE) | + static_cast(LogInfoFlag::FLAG_LOCAL) | + static_cast(LogInfoFlag::FLAG_KNOWLEDGE_VECTOR_WRITE); + int64_t expectCursor = 1; + CheckFlagAndCursor(db, schema.tableName, 1, expectFlag, expectCursor); + + /** + * @tc.steps: step5. update data with same content, flag and cursor unchanged + * @tc.expected: step5. Ok + */ + UpdateDBData(db, schema.tableName, 1, false); + CheckFlagAndCursor(db, schema.tableName, 1, expectFlag, expectCursor); + + EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); +} } -- Gitee