From 2b34446819877f162fb00e81d271f9395a22a1c8 Mon Sep 17 00:00:00 2001 From: zqq Date: Sat, 18 Jan 2025 17:10:31 +0800 Subject: [PATCH 1/5] fixbug in update Signed-off-by: zqq --- .../src/relational/relational_sync_data_inserter.cpp | 9 +++++++++ .../storage/distributeddb_rdb_collaboration_test.cpp | 10 ++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.cpp b/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.cpp index 699701a3f18..2236ec160e6 100644 --- a/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.cpp +++ b/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.cpp @@ -54,6 +54,7 @@ RelationalSyncDataInserter RelationalSyncDataInserter::CreateInserter(const std: inserter.SetRemoteFields(remoteFields); inserter.SetQuery(query); TableInfo localTable = localSchema.GetTable(query.GetTableName()); + localTable.SetDistributedTable(localSchema.GetDistributedTable(query.GetTableName())); inserter.SetLocalTable(localTable); inserter.SetTableMode(localSchema.GetTableMode()); if (localSchema.GetTableMode() == DistributedTableMode::COLLABORATION) { @@ -141,6 +142,10 @@ int RelationalSyncDataInserter::SaveData(bool isUpdate, const DataItem &dataItem for (const auto &primaryKey : localTable_.GetIdentifyKey()) { filterSet.insert(primaryKey); } + auto distributedPk = localTable_.GetSyncDistributedPk(); + if (!distributedPk.empty()) { + filterSet.insert(distributedPk.begin(), distributedPk.end()); + } } if (stmt == nullptr) { LOGW("skip save data %s", DBCommon::StringMiddleMasking(DBCommon::VectorToHexString(dataItem.hashKey)).c_str()); @@ -310,6 +315,10 @@ int RelationalSyncDataInserter::GetUpdateStatement(sqlite3 *db, sqlite3_stmt *&s for (const auto &primaryKey : localTable_.GetIdentifyKey()) { identifyKeySet.insert(primaryKey); } + auto distributedPk = localTable_.GetSyncDistributedPk(); + if (!distributedPk.empty()) { + identifyKeySet.insert(distributedPk.begin(), distributedPk.end()); + } std::string updateValue; const auto &localTableFields = localTable_.GetFields(); for (const auto &it : remoteFields_) { diff --git a/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp b/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp index ddd2128ec7b..e027c2aed55 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp @@ -1237,7 +1237,7 @@ HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync012, TestSize.Level0) tableSchema.name = DEVICE_SYNC_TABLE_AUTOINCREMENT; auto schema = GetSchema(); schema.tables.push_back(tableSchema); - auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema); deviceB_->SetDistributedSchema(distributedSchema); int errCode = SQLiteUtils::ExecuteRawSQL(db_, std::string("CREATE UNIQUE INDEX U_INDEX ON ") .append(tableSchema.name).append("('123')")); @@ -1248,7 +1248,9 @@ HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync012, TestSize.Level0) * @tc.steps: step2. Insert one data * @tc.expected: step2.ok */ - ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 1, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::InsertLocalDBData(0, 1, db_, tableSchema), E_OK); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // sleep 100 ms + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 2, deviceB_, tableSchema), E_OK); ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); /** * @tc.steps: step3. Sync to real device @@ -1259,7 +1261,7 @@ HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync012, TestSize.Level0) std::string sql = std::string("select count(*) from ").append(tableSchema.name); int count = 0; EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); - EXPECT_EQ(count, 1); + EXPECT_EQ(count, 2); /** * @tc.steps: step4. Update date and sync again * @tc.expected: step4.ok @@ -1269,6 +1271,6 @@ HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync012, TestSize.Level0) sql = std::string("select count(*) from ").append(tableSchema.name); count = 0; EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); - EXPECT_EQ(count, 1); + EXPECT_EQ(count, 2); } } \ No newline at end of file -- Gitee From 767d49da7ac7a579f6da97264e5c122d1a579c9e Mon Sep 17 00:00:00 2001 From: zqq Date: Tue, 21 Jan 2025 19:41:16 +0800 Subject: [PATCH 2/5] not support sync with unique col and pk Signed-off-by: zqq --- .../relational/sqlite_relational_utils.cpp | 24 ++ .../distributeddb_rdb_collaboration_test.cpp | 259 +++++++++++++++++- 2 files changed, 282 insertions(+), 1 deletion(-) diff --git a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp index 0c3b75d41c0..163a7c5557e 100644 --- a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp +++ b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp @@ -556,6 +556,27 @@ bool IsDistributedPkInvalid(const TableInfo &tableInfo, return false; } +bool IsDistributedSchemaSupport(const TableInfo &tableInfo, const std::vector &fields) +{ + if (!tableInfo.GetAutoIncrement()) { + return true; + } + bool isSyncPk = false; + bool isSyncOtherSpecified = false; + for (const auto &item : fields) { + if (tableInfo.IsPrimaryKey(item.colName) && item.isP2pSync) { + isSyncPk = true; + } else if (item.isSpecified && item.isP2pSync) { + isSyncOtherSpecified = true; + } + } + if (isSyncPk && isSyncOtherSpecified) { + LOGE("Not support sync with auto increment pk and other specified col"); + return false; + } + return true; +} + int CheckDistributedSchemaFields(const TableInfo &tableInfo, const std::vector &syncFields, const std::vector &fields) { @@ -563,6 +584,9 @@ int CheckDistributedSchemaFields(const TableInfo &tableInfo, const std::vector distributedPk; for (const auto &field : fields) { if (!tableInfo.IsFieldExist(field.colName)) { diff --git a/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp b/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp index e027c2aed55..52559962afc 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp @@ -726,10 +726,263 @@ HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema014, TestSize.Level0) distributedField.colName = "123"; distributedField.isSpecified = true; distributedTable.fields.push_back(distributedField); + distributedField.colName = "pk"; + distributedField.isP2pSync = false; + distributedTable.fields.push_back(distributedField); distributedSchema.tables.push_back(distributedTable); EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), SCHEMA_MISMATCH); } +/** + * @tc.name: SetSchema015 + * @tc.desc: Test call SetDistributedSchema with mark more than one unique col isSpecified true + * @tc.type: FUNC + * @tc.require: + * @tc.author: tankaisheng + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema015, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db, tableMode is COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + std::string createSql = "CREATE TABLE IF NOT EXISTS table_pk_int(integer_field INTEGER PRIMARY KEY AUTOINCREMENT," + "int_field INT, char_field CHARACTER(20) UNIQUE, clob_field CLOB UNIQUE, UNIQUE(char_field, clob_field));"; + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db_, createSql), E_OK); + EXPECT_EQ(delegate_->CreateDistributedTable("table_pk_int", TableSyncType::DEVICE_COOPERATION), OK); + + /** + * @tc.steps: step2. Test mark more than one unique col isSpecified true + * @tc.expected: step2. return SCHEMA_MISMATCH + */ + DistributedSchema distributedSchema = {0, {{"table_pk_int", { + {"integer_field", false, false}, + {"int_field", true, false}, + {"char_field", true, true}, + {"clob_field", true, true}}}}}; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), SCHEMA_MISMATCH); +} + +/** + * @tc.name: SetSchema016 + * @tc.desc: Test set isSpecified to false after isSpecified was set to true + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema016, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + std::string tableName = "multiPriKeyTable"; + std::string sql = "CREATE TABLE IF NOT EXISTS " + tableName + + "(pk1 INTEGER, pk2 INT, PRIMARY KEY (pk1, pk2));"; + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db_, sql), E_OK); + EXPECT_EQ(delegate_->CreateDistributedTable(tableName, TableSyncType::DEVICE_COOPERATION), OK); + /** + * @tc.steps: step2. Test set distributed schema + * @tc.expected: step2. return OK + */ + DistributedSchema schema1 = GetDistributedSchema(tableName, {"pk1", "pk2"}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema1), OK); + /** + * @tc.steps: step3. Test set distributed schema + * @tc.expected: step3. return SCHEMA_MISMATCH + */ + DistributedSchema schema2 = GetDistributedSchema(tableName, {"pk1", "pk2"}); + DistributedField &field2 = schema2.tables.front().fields.front(); + field2.isSpecified = true; + EXPECT_EQ(delegate_->SetDistributedSchema(schema2), SCHEMA_MISMATCH); +} + +int GetHashKey(sqlite3 *db, const std::string &tableName, std::vector &hashKeys) { + if (db == nullptr) { + return -E_INVALID_DB; + } + + std::string sql = "select cast(hash_key as text) from " + DBCommon::GetLogTableName(tableName); + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, sql, stmt); + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_OK)) { + LOGE("prepare statement failed(%d), sys(%d), msg(%s)", errCode, errno, sqlite3_errmsg(db)); + return errCode; + } + + do { + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + errCode = E_OK; + } else if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + LOGE("[SQLiteUtils][ExecuteSQL] execute statement failed(%d), sys(%d), msg(%s)", + errCode, errno, sqlite3_errmsg(db)); + } else { + const unsigned char *result = sqlite3_column_text(stmt, 0); + hashKeys.push_back(reinterpret_cast(result)); + } + } while (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)); + + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, true, ret); + return errCode; +} + +/** + * @tc.name: SetSchema017 + * @tc.desc: Test whether to update hash_key after setting up distributed schema + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema017, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + std::string tableName = "multiPriKeyTable"; + std::string sql = "CREATE TABLE IF NOT EXISTS " + tableName + + "(pk1 INTEGER PRIMARY KEY AUTOINCREMENT, pk2 INT UNIQUE);"; + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db_, sql), E_OK); + EXPECT_EQ(delegate_->CreateDistributedTable(tableName, TableSyncType::DEVICE_COOPERATION), OK); + /** + * @tc.steps: step2. Insert a record and get hash_key + * @tc.expected: step2.ok + */ + int dataCount = 10; + for (int i = 0; i < dataCount; i++) { + sql = "insert into " + tableName + " values (" + std::to_string(i) + ", " + std::to_string(i + 1) + ");"; + EXPECT_EQ(SQLiteUtils::ExecuteRawSQL(db_, sql), E_OK); + } + std::vector oldHashKeys; + EXPECT_EQ(GetHashKey(db_, tableName, oldHashKeys), E_OK); + ASSERT_EQ(oldHashKeys.size(), static_cast(dataCount)); + /** + * @tc.steps: step3. Set distributed schema and get old hash_key + * @tc.expected: step3.ok + */ + DistributedSchema schema1 = GetDistributedSchema(tableName, {"pk1", "pk2"}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema1), OK); + std::vector newHashKeys1; + EXPECT_EQ(GetHashKey(db_, tableName, newHashKeys1), E_OK); + ASSERT_EQ(newHashKeys1.size(), static_cast(dataCount)); + for (int i = 0; i < dataCount; i++) { + EXPECT_EQ(oldHashKeys[i], newHashKeys1[i]); + } + /** + * @tc.steps: step4. Set another distributed schema and get old hash_key + * @tc.expected: step4.ok + */ + DistributedSchema schema2 = {0, {{"multiPriKeyTable", { + {"pk1", false, false}, + {"pk2", true, true}}}}}; + EXPECT_EQ(delegate_->SetDistributedSchema(schema2), OK); + std::vector newHashKeys2; + EXPECT_EQ(GetHashKey(db_, tableName, newHashKeys2), E_OK); + ASSERT_EQ(newHashKeys2.size(), static_cast(dataCount)); + for (int i = 0; i < dataCount; i++) { + EXPECT_NE(newHashKeys1[i], newHashKeys2[i]); + } +} + +/** + * @tc.name: SetSchema018 + * @tc.desc: Test no primary key table setting isSpecified + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema018, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + std::string tableName = "noPriKeyTable"; + std::string sql = "CREATE TABLE IF NOT EXISTS " + tableName + + "(field_int1 INTEGER, field_int2 INT);"; + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db_, sql), E_OK); + EXPECT_EQ(delegate_->CreateDistributedTable(tableName, TableSyncType::DEVICE_COOPERATION), OK); + /** + * @tc.steps: step2. Test set distributed schema + * @tc.expected: step2. return SCHEMA_MISMATCH + */ + DistributedSchema schema = GetDistributedSchema(tableName, {"field_int1"}); + DistributedField &field = schema.tables.front().fields.front(); + field.isSpecified = true; + EXPECT_EQ(delegate_->SetDistributedSchema(schema), SCHEMA_MISMATCH); +} + +/** + * @tc.name: SetSchema019 + * @tc.desc: Test call SetDistributedSchema when unique col not set isP2pSync + * @tc.type: FUNC + * @tc.require: + * @tc.author: tankaisheng + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema019, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db, tableMode is COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + std::string createSql = "CREATE TABLE IF NOT EXISTS table_pk_integer(integer_field INTEGER UNIQUE," + "int_field INT, char_field CHARACTER(20), clob_field CLOB);"; + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db_, createSql), E_OK); + EXPECT_EQ(delegate_->CreateDistributedTable("table_pk_integer", TableSyncType::DEVICE_COOPERATION), OK); + + /** + * @tc.steps: step2. Test mark unique col isP2pSync true + * @tc.expected: step2. return SCHEMA_MISMATCH + */ + DistributedSchema distributedSchema = {1, {{"table_pk_integer", { + {"int_field", true}, + {"char_field", true}, + {"clob_field", true}}}}}; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), SCHEMA_MISMATCH); +} + +/** + * @tc.name: SetSchema020 + * @tc.desc: Test call SetDistributedSchema when unique col and pk isP2pSync + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema020, TestSize.Level0) +{ + + /** + * @tc.steps: step1. Prepare db, tableMode is COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + std::string createSql = "CREATE TABLE IF NOT EXISTS table_pk_int(integer_field INTEGER PRIMARY KEY AUTOINCREMENT," + "int_field INT UNIQUE, char_field CHARACTER(20), clob_field CLOB);"; + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db_, createSql), E_OK); + EXPECT_EQ(delegate_->CreateDistributedTable("table_pk_int", TableSyncType::DEVICE_COOPERATION), OK); + + /** + * @tc.steps: step2. Test mark unique col and pk isP2pSync true, specified unique col + * @tc.expected: step2. return NOT_SUPPORT + */ + DistributedSchema distributedSchema = {1, { + {"table_pk_int", { + {"integer_field", true}, + {"int_field", true, true}, + {"char_field", true}, + {"clob_field", true} + }}} + }; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), NOT_SUPPORT); +} + /** * @tc.name: NormalSync001 * @tc.desc: Test set distributed schema and sync. @@ -1237,7 +1490,11 @@ HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync012, TestSize.Level0) tableSchema.name = DEVICE_SYNC_TABLE_AUTOINCREMENT; auto schema = GetSchema(); schema.tables.push_back(tableSchema); - auto distributedSchema = RDBDataGenerator::ParseSchema(schema); + DistributedSchema distributedSchema = {0, {{tableSchema.name, { + {"pk", false, false}, + {"int_field1", true, false}, + {"int_field2", true, false}, + {"123", true, true}}}}}; deviceB_->SetDistributedSchema(distributedSchema); int errCode = SQLiteUtils::ExecuteRawSQL(db_, std::string("CREATE UNIQUE INDEX U_INDEX ON ") .append(tableSchema.name).append("('123')")); -- Gitee From 46608b48445d229c10f34426cb452f79a0274aa0 Mon Sep 17 00:00:00 2001 From: zqq Date: Wed, 22 Jan 2025 14:37:24 +0800 Subject: [PATCH 3/5] no support diff specified field sync Signed-off-by: zqq --- .../common/include/schema_negotiate.h | 6 + .../common/src/schema_negotiate.cpp | 47 ++++ .../distributeddb_rdb_collaboration_test.cpp | 236 ++++++++++++++++++ 3 files changed, 289 insertions(+) diff --git a/frameworks/libs/distributeddb/common/include/schema_negotiate.h b/frameworks/libs/distributeddb/common/include/schema_negotiate.h index 2908c6ddb6e..00ea46caef4 100644 --- a/frameworks/libs/distributeddb/common/include/schema_negotiate.h +++ b/frameworks/libs/distributeddb/common/include/schema_negotiate.h @@ -61,6 +61,12 @@ private: static RelationalSyncOpinion MakeOpinionEachTable(const RelationalSchemaObject &localSchema, const RelationalSchemaObject &remoteSchema); + + static bool IsDistributedSchemaInvalid(const RelationalSchemaObject &localSchema, + const RelationalSchemaObject &remoteSchema); + + static bool IsDistributedTableInvalid(const DistributedTable &local, const DistributedTable &remote, + const TableInfo &localTable, const TableInfo &remoteTable); }; } diff --git a/frameworks/libs/distributeddb/common/src/schema_negotiate.cpp b/frameworks/libs/distributeddb/common/src/schema_negotiate.cpp index 3c9d0fb38dc..95e05f9c3ae 100644 --- a/frameworks/libs/distributeddb/common/src/schema_negotiate.cpp +++ b/frameworks/libs/distributeddb/common/src/schema_negotiate.cpp @@ -165,6 +165,9 @@ RelationalSyncOpinion SchemaNegotiate::MakeLocalSyncOpinion(const RelationalSche return {}; } + if (IsDistributedSchemaInvalid(localSchema, remoteSchemaObj)) { + return {}; + } return MakeOpinionEachTable(localSchema, remoteSchemaObj); } @@ -263,4 +266,48 @@ int SchemaNegotiate::DeserializeData(Parcel &parcel, RelationalSyncOpinion &opin } return parcel.IsError() ? -E_INVALID_ARGS : E_OK; } + +bool SchemaNegotiate::IsDistributedSchemaInvalid(const RelationalSchemaObject &localSchema, + const RelationalSchemaObject &remoteSchema) +{ + auto localTables = localSchema.GetTableNames(); + for (const auto &localTable : localTables) { + auto localDistributedTable = localSchema.GetDistributedTable(localTable); + if (localDistributedTable.tableName.empty()) { + continue; + } + auto remoteDistributedTable = remoteSchema.GetDistributedTable(localTable); + if (remoteDistributedTable.tableName.empty()) { + continue; + } + if (IsDistributedTableInvalid(localDistributedTable, remoteDistributedTable, + localSchema.GetTable(localTable), remoteSchema.GetTable(localTable))) { + return true; + } + } + return false; +} + +bool SchemaNegotiate::IsDistributedTableInvalid(const DistributedTable &local, const DistributedTable &remote, + const TableInfo &localTable, const TableInfo &remoteTable) +{ + std::set localSpecified; + for (const auto &item : local.fields) { + if (item.isP2pSync && item.isSpecified && !localTable.IsPrimaryKey(item.colName)) { + localSpecified.insert(item.colName); + } + } + std::set remoteSpecified; + for (const auto &item : remote.fields) { + if (item.isP2pSync && item.isSpecified && !remoteTable.IsPrimaryKey(item.colName)) { + remoteSpecified.insert(item.colName); + } + } + if (localSpecified != remoteSpecified) { + LOGE("[SchemaNegotiate] specified field is diff local size %zu remote size %zu", + localSpecified.size(), remoteSpecified.size()); + return true; + } + return false; +} } \ No newline at end of file diff --git a/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp b/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp index 52559962afc..14b06885a94 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp @@ -1530,4 +1530,240 @@ HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync012, TestSize.Level0) EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); EXPECT_EQ(count, 2); } + +/** + * @tc.name: NormalSync013 + * @tc.desc: Test chanage data after sync. + * @tc.type: FUNC + * @tc.require: + * @tc.author: lg + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync013, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + deviceB_->SetDistributedSchema(distributedSchema); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + /** + * @tc.steps: step2. Insert one data + * @tc.expected: step2.ok + */ + auto tableSchema = GetTableSchema(); + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 10, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device + * @tc.expected: step3.ok + */ + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + /** + * @tc.steps: step4. check changData + * @tc.expected: step4.ok + */ + auto changeData = delegateObserver_->GetSavedChangedData(); + EXPECT_EQ(changeData[tableSchema.name].primaryData[0].size(), 10u); + EXPECT_EQ(changeData[tableSchema.name].field.size(), 1u); +} + +/** + * @tc.name: NormalSync014 + * @tc.desc: Test chanage data after sync. + * @tc.type: FUNC + * @tc.require: + * @tc.author: tankaisheng + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync014, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + deviceB_->SetDistributedSchema(distributedSchema); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + DistributedSchema schema1 = GetDistributedSchema(DEVICE_SYNC_TABLE, {"int_field1"}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema1), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_COOPERATION); + /** + * @tc.steps: step2. Insert data + * @tc.expected: step2.ok + */ + auto tableSchema = GetTableSchema(); + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 10, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device + * @tc.expected: step3.ok + */ + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + /** + * @tc.steps: step4. check changData + * @tc.expected: step4.ok + */ + auto changeData = delegateObserver_->GetSavedChangedData(); + EXPECT_EQ(changeData[tableSchema.name].primaryData[0].size(), 10u); + EXPECT_EQ(changeData[tableSchema.name].field.size(), 1u); + /** + * @tc.steps: step5. SetDistributedSchema again + * @tc.expected: step5.ok + */ + DistributedSchema schema2 = GetDistributedSchema(DEVICE_SYNC_TABLE, {"int_field1", "int_field2"}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema2), OK); + /** + * @tc.steps: step6. Sync to real device + * @tc.expected: step6.ok + */ + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + /** + * @tc.steps: step7. check changData + * @tc.expected: step7.ok + */ + changeData = delegateObserver_->GetSavedChangedData(); + EXPECT_EQ(changeData[tableSchema.name].primaryData[1].size(), 10u); + EXPECT_EQ(changeData[tableSchema.name].field.size(), 1u); +} + +/** + * @tc.name: NormalSync015 + * @tc.desc: Test sync with multi primary key table. + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync015, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + std::string tableName = "multiPriKeyTable"; + std::string sql = "CREATE TABLE IF NOT EXISTS " + tableName + + "(pk1 INTEGER, pk2 INT, PRIMARY KEY (pk1, pk2));"; + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db_, sql), E_OK); + /** + * @tc.steps: step2. Create distributed table and set distributed schema + * @tc.expected: step2.ok + */ + auto distributedSchema = GetDistributedSchema(tableName, {"pk1", "pk2"}); + deviceB_->SetDistributedSchema(distributedSchema); + EXPECT_EQ(delegate_->CreateDistributedTable(tableName, TableSyncType::DEVICE_COOPERATION), OK); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + /** + * @tc.steps: step3. Init data and sync to real device + * @tc.expected: step3.ok + */ + TableSchema tableSchema; + tableSchema.name = tableName; + Field field; + field.primary = true; + field.type = TYPE_INDEX; + field.colName = "pk1"; + tableSchema.fields.push_back(field); + field.colName = "pk2"; + tableSchema.fields.push_back(field); + uint32_t dataCount = 10; + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, dataCount, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableName, db_, deviceB_), E_OK); + Query query = Query::Select(tableName); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + /** + * @tc.steps: step4. check changData + * @tc.expected: step4.ok + */ + auto changeData = delegateObserver_->GetSavedChangedData(); + ASSERT_EQ(changeData[tableName].primaryData[OP_INSERT].size(), dataCount); + for (uint32_t i = 0; i < dataCount; i++) { + EXPECT_EQ(changeData[tableName].primaryData[OP_INSERT][i].size(), 3u); // primary key (pk1, pk2) and rowid + } + EXPECT_EQ(changeData[tableName].field.size(), 3u); // primary key (pk1, pk2) and rowid +} + +/** + * @tc.name: NormalSync016 + * @tc.desc: Test sync with diff specified field. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync016, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db, tableMode is COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + std::string createSql = "CREATE TABLE IF NOT EXISTS table_int(integer_field INTEGER PRIMARY KEY AUTOINCREMENT," + "int_field1 INT UNIQUE, int_field2 INT UNIQUE);"; + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db_, createSql), E_OK); + EXPECT_EQ(delegate_->CreateDistributedTable("table_int", TableSyncType::DEVICE_COOPERATION), OK); + + /** + * @tc.steps: step2. Test mark one specified one is field1 another is field2 + * @tc.expected: step2. sync return SCHEMA_MISMATCH + */ + DistributedSchema distributedSchema = {0, {{"table_int", { + {"integer_field", false, false}, + {"int_field1", true, false}, + {"int_field2", true, true}}}}}; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + distributedSchema = {0, {{"table_int", { + {"integer_field", false, false}, + {"int_field1", true, true}, + {"int_field2", true, false}}}}}; + deviceB_->SetDistributedSchema(distributedSchema); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv("table_int", db_, deviceB_), E_OK); + Query query = Query::Select("table_int"); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, SCHEMA_MISMATCH, + {deviceB_->GetDeviceId()}); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PUSH_ONLY, SCHEMA_MISMATCH, + {deviceB_->GetDeviceId()}); +} + +/** + * @tc.name: InvalidSync001 + * @tc.desc: Test remote set empty distributed schema and sync. + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBRDBCollaborationTest, InvalidSync001, TestSize.Level0) { + /** + * @tc.steps: step1. Remote device set empty distributed schema + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + DistributedSchema emptySchema; + deviceB_->SetDistributedSchema(emptySchema); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + /** + * @tc.steps: step2. Insert one data + * @tc.expected: step2.ok + */ + auto tableSchema = GetTableSchema(); + EXPECT_EQ(RDBDataGenerator::InsertLocalDBData(0, 1, db_, GetTableSchema()), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device + * @tc.expected: step3.SCHEMA_MISMATCH + */ + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PUSH_ONLY, SCHEMA_MISMATCH, + {deviceB_->GetDeviceId()}); +} } \ No newline at end of file -- Gitee From 76f261c0977031814c6b8ac22aa597b791a17590 Mon Sep 17 00:00:00 2001 From: zqq Date: Thu, 23 Jan 2025 16:31:39 +0800 Subject: [PATCH 4/5] not support remove device data in COLLABORATION Signed-off-by: zqq --- .../sqlite/relational/sqlite_relational_store.cpp | 14 ++++++++++++++ .../distributeddb_rdb_collaboration_test.cpp | 10 +++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp index b1e7aa986db..bbeab134cd2 100644 --- a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp +++ b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp @@ -499,6 +499,13 @@ int SQLiteRelationalStore::CleanCloudData(ClearMode mode) int SQLiteRelationalStore::RemoveDeviceData() { + auto mode = static_cast(sqliteStorageEngine_->GetProperties().GetIntProp( + RelationalDBProperties::DISTRIBUTED_TABLE_MODE, static_cast(DistributedTableMode::SPLIT_BY_DEVICE))); + if (mode == DistributedTableMode::COLLABORATION) { + LOGE("Not support remove all device data in collaboration mode."); + return -E_NOT_SUPPORT; + } + std::vector tableNameList = GetAllDistributedTableName(); if (tableNameList.empty()) { return E_OK; @@ -543,6 +550,13 @@ int SQLiteRelationalStore::RemoveDeviceData() int SQLiteRelationalStore::RemoveDeviceData(const std::string &device, const std::string &tableName) { + auto mode = static_cast(sqliteStorageEngine_->GetProperties().GetIntProp( + RelationalDBProperties::DISTRIBUTED_TABLE_MODE, static_cast(DistributedTableMode::SPLIT_BY_DEVICE))); + if (mode == DistributedTableMode::COLLABORATION) { + LOGE("Not support remove device data in collaboration mode."); + return -E_NOT_SUPPORT; + } + TableInfoMap tables = sqliteStorageEngine_->GetSchema().GetTables(); // TableInfoMap auto iter = tables.find(tableName); if (tables.empty() || (!tableName.empty() && iter == tables.end())) { diff --git a/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp b/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp index 14b06885a94..7dd5c7b0fb0 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp @@ -1738,7 +1738,8 @@ HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync016, TestSize.Level0) * @tc.require: * @tc.author: bty */ -HWTEST_F(DistributedDBRDBCollaborationTest, InvalidSync001, TestSize.Level0) { +HWTEST_F(DistributedDBRDBCollaborationTest, InvalidSync001, TestSize.Level0) +{ /** * @tc.steps: step1. Remote device set empty distributed schema * @tc.expected: step1.ok @@ -1765,5 +1766,12 @@ HWTEST_F(DistributedDBRDBCollaborationTest, InvalidSync001, TestSize.Level0) { Query query = Query::Select(tableSchema.name); DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PUSH_ONLY, SCHEMA_MISMATCH, {deviceB_->GetDeviceId()}); + /** + * @tc.steps: step4. Remove device data + * @tc.expected: step4. NOT_SUPPORT + */ + EXPECT_EQ(delegate_->RemoveDeviceData("dev", DEVICE_SYNC_TABLE), NOT_SUPPORT); + EXPECT_EQ(delegate_->RemoveDeviceData(), NOT_SUPPORT); + EXPECT_EQ(delegate_->RemoveDeviceData("dev", ClearMode::DEFAULT), NOT_SUPPORT); } } \ No newline at end of file -- Gitee From a356e0d01315c67fa71570dc2f97b1232394cd17 Mon Sep 17 00:00:00 2001 From: zqq Date: Thu, 23 Jan 2025 20:18:57 +0800 Subject: [PATCH 5/5] set label before import Signed-off-by: zqq --- .../storage/src/operation/database_oper.cpp | 11 +++-- .../storage/src/operation/database_oper.h | 5 +- ...eddb_interfaces_import_and_export_test.cpp | 48 +++++++++++++++++++ 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/frameworks/libs/distributeddb/storage/src/operation/database_oper.cpp b/frameworks/libs/distributeddb/storage/src/operation/database_oper.cpp index 43983472c82..39b70b6e58f 100644 --- a/frameworks/libs/distributeddb/storage/src/operation/database_oper.cpp +++ b/frameworks/libs/distributeddb/storage/src/operation/database_oper.cpp @@ -150,8 +150,13 @@ int DatabaseOper::RekeyRecover(const KvDBProperties &property) return E_OK; } -int DatabaseOper::CheckSecurityOption(const std::string &filePath, const KvDBProperties &property) const +int DatabaseOper::CheckSecurityOption(const std::string &filePath, const KvDBProperties &property) { + SecurityOption dbSecOpt; + dbSecOpt.securityFlag = property.GetSecFlag(); + dbSecOpt.securityLabel = property.GetSecLabel(); + // set backup file security label first, avoid file loss label + (void)RuntimeContext::GetInstance()->SetSecurityOption(filePath, dbSecOpt); SecurityOption secOption; int errCode = RuntimeContext::GetInstance()->GetSecurityOption(filePath, secOption); if (errCode != E_OK && errCode != -E_NOT_SUPPORT) { @@ -159,10 +164,6 @@ int DatabaseOper::CheckSecurityOption(const std::string &filePath, const KvDBPro return errCode; } - SecurityOption dbSecOpt; - dbSecOpt.securityFlag = property.GetSecFlag(); - dbSecOpt.securityLabel = property.GetSecLabel(); - if (dbSecOpt == secOption || secOption.securityLabel == SecurityLabel::NOT_SET) { return E_OK; } diff --git a/frameworks/libs/distributeddb/storage/src/operation/database_oper.h b/frameworks/libs/distributeddb/storage/src/operation/database_oper.h index c46ef085b6d..eaaae5462e7 100644 --- a/frameworks/libs/distributeddb/storage/src/operation/database_oper.h +++ b/frameworks/libs/distributeddb/storage/src/operation/database_oper.h @@ -72,7 +72,6 @@ protected: // export begin int ExecuteExport(const std::string &filePath, const CipherPassword &passwd, const KvDBProperties &property) const; - private: int CreateStatusCtrlFile(const KvDBProperties &property, std::string &orgCtrlFile, std::string &newCtrlFile); @@ -98,10 +97,10 @@ private: int PackExportedDatabase(const std::string &fileDir, const std::string &packedFile, const KvDBProperties &property) const; - int CheckSecurityOption(const std::string &filePath, const KvDBProperties &property) const; - int CreateBackupDirForExport(const KvDBProperties &property, std::string ¤tDir, std::string &backupDir) const; + static int CheckSecurityOption(const std::string &filePath, const KvDBProperties &property); + std::string deviceId_; }; } // namespace DistributedDB diff --git a/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_import_and_export_test.cpp b/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_import_and_export_test.cpp index 4bc4836b1f6..1b3ba0b3e48 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_import_and_export_test.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_import_and_export_test.cpp @@ -1365,4 +1365,52 @@ HWTEST_F(DistributedDBInterfacesImportAndExportTest, ImportTest001, TestSize.Lev EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK); EXPECT_EQ(g_mgr.DeleteKvStore(singleStoreId), OK); } + + +/** + * @tc.name: CheckSecurityLabel001 + * @tc.desc: Test check label with set label. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBInterfacesImportAndExportTest, CheckSecurityLabel001, TestSize.Level0) +{ + std::shared_ptr adapter = std::make_shared(); + RuntimeContext::GetInstance()->SetProcessSystemApiAdapter(adapter); + /** + * @tc.steps: step1. Pre-create folder dir + */ + std::string singleFileName = g_exportFileDir + "/CheckSecurityLabel001.$$"; + std::string singleStoreId = "distributed_CheckSecurityLabel001"; + KvStoreNbDelegate::Option option = {true, false, false}; + option.secOption = {SecurityLabel::S1, SecurityFlag::ECE}; + g_mgr.GetKvStore(singleStoreId, option, g_kvNbDelegateCallback); + ASSERT_TRUE(g_kvNbDelegatePtr != nullptr); + EXPECT_TRUE(g_kvDelegateStatus == OK); + /** + * @tc.steps: step2. Specify the path to export the non-encrypted board database. + * @tc.expected: step2. Returns OK + */ + CipherPassword passwd; + EXPECT_EQ(g_kvNbDelegatePtr->Export(singleFileName, passwd), OK); + /** + * @tc.steps: step3. Clear label before import and import again. + * @tc.expected: step3. Import will set label + */ + SecurityOption before; + adapter->GetSecurityOption(singleFileName, before); + adapter->ResetSecOptDic(); + EXPECT_EQ(g_kvNbDelegatePtr->Import(singleFileName, passwd), OK); + SecurityOption after; + adapter->GetSecurityOption(singleFileName, before); + EXPECT_NE(before, after); + /** + * @tc.steps: step4. Release resource. + * @tc.expected: step4. OK + */ + EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK); + EXPECT_EQ(g_mgr.DeleteKvStore(singleStoreId), OK); + RuntimeContext::GetInstance()->SetProcessSystemApiAdapter(nullptr); +} #endif // OMIT_ENCRYPT -- Gitee