diff --git a/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_client.h b/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_client.h index 1be216ce362dad12eb744f657f7bed0f1fcdd602..cc03e7017b5980b2363700cf70ac03530acae359 100644 --- a/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_client.h +++ b/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_client.h @@ -64,6 +64,7 @@ struct KnowledgeSourceSchema { std::string tableName; std::set extendColNames; std::set knowledgeColNames; + std::map> columnsToVerify; }; } 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 4a496f447aaef52c1ceba329242db69e3cdd2a96..87bb5320ee24f76ff9d243fb4194858c3c0830e3 100644 --- a/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.cpp +++ b/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.cpp @@ -16,6 +16,7 @@ #include "db_common.h" #include "db_errno.h" +#include "res_finalizer.h" #include "simple_tracker_log_table_manager.h" #include "sqlite_relational_utils.h" #include "sqlite_utils.h" @@ -49,6 +50,52 @@ TrackerSchema GetTrackerSchema(const KnowledgeSourceSchema &schema) } } +constexpr const char *PROCESS_SEQ_KEY = "processSequence"; + +int KnowledgeSourceUtils::CheckProcessSequence(sqlite3 *db, const std::string &tableName, + const std::string &columnName) +{ + // empty column name is ok + if (columnName.empty()) { + return E_OK; + } + if (db == nullptr) { + return -E_INVALID_DB; + } + std::string checkColumnSql = "SELECT COUNT(1) FROM pragma_table_info('" + tableName + "')" + + " WHERE name = ? AND type LIKE '%int%'"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, checkColumnSql, stmt); + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_OK)) { + LOGE("Get check column statement failed. 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 column type %d", ret); + } + }); + + errCode = SQLiteUtils::BindTextToStatement(stmt, 1, columnName); + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_OK)) { + LOGE("Bind column name to statement failed. err=%d", errCode); + return errCode; + } + + errCode = SQLiteUtils::StepWithRetry(stmt); + // should always return a row of data + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + LOGE("Check column type failed. err=%d", errCode); + return errCode; + } + bool isCheckSuccess = (sqlite3_column_int(stmt, 0) == 1); + return isCheckSuccess ? E_OK : -E_INVALID_ARGS; +} + int KnowledgeSourceUtils::SetKnowledgeSourceSchema(sqlite3 *db, const KnowledgeSourceSchema &schema) { int errCode = SQLiteUtils::BeginTransaction(db, TransactType::IMMEDIATE); @@ -89,17 +136,39 @@ int KnowledgeSourceUtils::CleanDeletedData(sqlite3 *db, const std::string &table return errCode; } -int KnowledgeSourceUtils::SetKnowledgeSourceSchemaInner(sqlite3 *db, const KnowledgeSourceSchema &schema) +int KnowledgeSourceUtils::CheckSchemaFields(sqlite3 *db, const KnowledgeSourceSchema &schema) { - bool isExist = false; - auto errCode = SQLiteUtils::CheckTableExists(db, schema.tableName, isExist); + bool isCheckSuccess = false; + auto errCode = SQLiteUtils::CheckTableExists(db, schema.tableName, isCheckSuccess); if (errCode != E_OK) { return errCode; } - if (!isExist) { + if (!isCheckSuccess) { LOGE("Set not exist table's knowledge schema"); return -E_INVALID_ARGS; } + + auto it = schema.columnsToVerify.find(PROCESS_SEQ_KEY); + if (it == schema.columnsToVerify.end()) { + return E_OK; + } + for (const auto &columnName : it->second) { + errCode = CheckProcessSequence(db, schema.tableName, columnName); + if (errCode != E_OK) { + LOGE("column type not match, name %s, size %zu", DBCommon::StringMiddleMasking(columnName).c_str(), + columnName.size()); + return errCode; + } + } + return E_OK; +} + +int KnowledgeSourceUtils::SetKnowledgeSourceSchemaInner(sqlite3 *db, const KnowledgeSourceSchema &schema) +{ + int errCode = CheckSchemaFields(db, schema); + if (errCode != E_OK) { + return errCode; + } errCode = InitMeta(db, schema.tableName); 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 a7a5c141e0dbd30e3e3a93c47a0c040c3ff45724..34e2e24a306a65ea4941a71ba4bca8e8cff9f20e 100644 --- a/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.h +++ b/frameworks/libs/distributeddb/interfaces/src/relational/knowledge_source_utils.h @@ -32,6 +32,10 @@ public: static int CleanDeletedData(sqlite3 *db, const std::string &tableName, uint64_t cursor); protected: + static int CheckProcessSequence(sqlite3 *db, const std::string &tableName, const std::string &columnName); + + static int CheckSchemaFields(sqlite3 *db, const KnowledgeSourceSchema &schema); + static int SetKnowledgeSourceSchemaInner(sqlite3 *db, const KnowledgeSourceSchema &schema); static int InitMeta(sqlite3 *db, const std::string &table); 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 c41b83c2da5ef8d4df78bbb6b365356026a31fd7..49a6e82a47566fa049899f1ec7d7f9177908baf7 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 @@ -252,4 +252,61 @@ HWTEST_F(DistributedDBRDBKnowledgeClientTest, SetKnowledge003, TestSize.Level0) EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); } + +/** + * @tc.name: SetKnowledge004 + * @tc.desc: Test set knowledge schema with sort column. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suyuchen + */ +HWTEST_F(DistributedDBRDBKnowledgeClientTest, SetKnowledge004, TestSize.Level0) +{ + /** + * @tc.steps: step1. Set knowledge source schema when sort column has type int. + * @tc.expected: step1. Ok + */ + UtTableSchemaInfo tableInfo = GetTableSchema(KNOWLEDGE_TABLE); + + // add a non-integer field + UtFieldInfo field; + field.field.colName = "string_field"; + field.field.type = TYPE_INDEX; + field.field.primary = false; + tableInfo.fieldInfo.push_back(field); + + sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX); + ASSERT_NE(db, nullptr); + RDBDataGenerator::InitTableWithSchemaInfo(tableInfo, *db); + KnowledgeSourceSchema schema; + schema.tableName = KNOWLEDGE_TABLE; + schema.columnsToVerify = {}; + schema.extendColNames.insert("id"); + schema.knowledgeColNames.insert("int_field1"); + schema.knowledgeColNames.insert("int_field2"); + EXPECT_EQ(SetKnowledgeSourceSchema(db, schema), OK); + + /** + * @tc.steps: step2. Set knowledge source schema when sort column not exist. + * @tc.expected: step2. INVALID_ARGS + */ + schema.columnsToVerify = {{"processSequence", {"not_exist"}}}; + EXPECT_EQ(SetKnowledgeSourceSchema(db, schema), INVALID_ARGS); + + /** + * @tc.steps: step3. Set knowledge source schema when sort column is not integer. + * @tc.expected: step3. INVALID_ARGS + */ + schema.columnsToVerify = {{"processSequence", {"string_field"}}}; + EXPECT_EQ(SetKnowledgeSourceSchema(db, schema), INVALID_ARGS); + + /** + * @tc.steps: step4. Set knowledge source schema when sort column empty. + * @tc.expected: step4. OK + */ + schema.columnsToVerify = {{"processSequence", {"", "id", "int_field1"}}}; + EXPECT_EQ(SetKnowledgeSourceSchema(db, schema), OK); + + EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); +} }