From 7151ffc967f15a51f46c14a4615fc2ebf3e3bf39 Mon Sep 17 00:00:00 2001 From: htt1997 Date: Mon, 28 Oct 2024 19:53:53 +0800 Subject: [PATCH] update Signed-off-by: htt1997 --- .../api/@ohos.data.relationalStore.d.ts | 111 +- .../napi/cloud_data/include/js_error_utils.h | 2 + .../include/napi_rdb_context.h | 3 +- .../include/napi_rdb_js_utils.h | 7 + .../relationalstore/src/napi_rdb_error.cpp | 12 + .../relationalstore/src/napi_rdb_js_utils.cpp | 9 + .../relationalstore/src/napi_rdb_store.cpp | 17 +- .../dfx/include/rdb_fault_hiview_reporter.h | 2 +- .../native/rdb/include/connection_pool.h | 6 +- .../native/rdb/include/grd_api_manager.h | 43 +- .../frameworks/native/rdb/include/grd_error.h | 26 + .../native/rdb/include/grd_type_export.h | 4 + .../native/rdb/include/rd_connection.h | 7 +- .../frameworks/native/rdb/include/rd_utils.h | 15 +- .../native/rdb/include/transaction_impl.h | 4 + .../native/rdb/src/connection_pool.cpp | 35 +- .../native/rdb/src/grd_api_manager.cpp | 1 + .../native/rdb/src/rd_connection.cpp | 109 +- .../frameworks/native/rdb/src/rd_utils.cpp | 120 +- .../frameworks/native/rdb/src/rdb_store.cpp | 18 +- .../native/rdb/src/rdb_store_config.cpp | 10 +- .../native/rdb/src/rdb_store_impl.cpp | 80 +- .../native/rdb/src/rdb_store_manager.cpp | 4 - .../native/rdb/src/sqlite_connection.cpp | 2 +- .../native/rdb/src/transaction_impl.cpp | 24 + .../inner_api/rdb/include/rdb_store_config.h | 13 +- .../inner_api/rdb/include/transaction.h | 22 + .../rdb/mock/include/rdb_store_config.h | 7 +- .../src/RdbStoreTransInsertJsunit.test.js | 945 ++++++++ .../unittest/src/RdbStoreTransJsunit.test.js | 1986 +++++++++++++++++ .../unittest/src/RdbStoreTransaction.test.js | 298 ++- .../src/RdbstoreEncryptionJsunit.test.js | 69 +- relational_store/test/native/rdb/BUILD.gn | 1 + .../rdb/unittest/rdb_execute_rd_test.cpp | 921 ++++++++ .../rdb/unittest/rdb_store_impl_test.cpp | 2 +- .../native/rdb/unittest/rdb_trans_db_test.cpp | 62 + .../native/rdb/unittest/transaction_test.cpp | 304 ++- 37 files changed, 5022 insertions(+), 279 deletions(-) create mode 100644 relational_store/test/js/relationalstore/unittest/src/RdbStoreTransInsertJsunit.test.js create mode 100644 relational_store/test/js/relationalstore/unittest/src/RdbStoreTransJsunit.test.js create mode 100644 relational_store/test/native/rdb/unittest/rdb_execute_rd_test.cpp diff --git a/interface_sdk/api/@ohos.data.relationalStore.d.ts b/interface_sdk/api/@ohos.data.relationalStore.d.ts index da96b2ad..cbaa8eaa 100644 --- a/interface_sdk/api/@ohos.data.relationalStore.d.ts +++ b/interface_sdk/api/@ohos.data.relationalStore.d.ts @@ -1462,20 +1462,20 @@ declare namespace relationalStore { } /** - * Create transaction option. + * Create transaction options. * - * @interface TransactionOption + * @interface TransactionOptions * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @since 14 */ - interface TransactionOption { + interface TransactionOptions { /** * The type of transaction. * * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @since 14 */ - transactionType: TransactionType; + transactionType?: TransactionType; } /** @@ -4047,10 +4047,10 @@ declare namespace relationalStore { * @since 12 */ update( - values: ValuesBucket, - predicates: RdbPredicates, - conflict: ConflictResolution, - callback: AsyncCallback + values: ValuesBucket, + predicates: RdbPredicates, + conflict: ConflictResolution, + callback: AsyncCallback ): void; /** @@ -4275,10 +4275,10 @@ declare namespace relationalStore { * @since 12 */ update( - table: string, - values: ValuesBucket, - predicates: dataSharePredicates.DataSharePredicates, - callback: AsyncCallback + table: string, + values: ValuesBucket, + predicates: dataSharePredicates.DataSharePredicates, + callback: AsyncCallback ): void; /** @@ -4822,10 +4822,10 @@ declare namespace relationalStore { * @since 12 */ query( - table: string, - predicates: dataSharePredicates.DataSharePredicates, - columns: Array, - callback: AsyncCallback + table: string, + predicates: dataSharePredicates.DataSharePredicates, + columns: Array, + callback: AsyncCallback ): void; /** @@ -4865,9 +4865,9 @@ declare namespace relationalStore { * @since 12 */ query( - table: string, - predicates: dataSharePredicates.DataSharePredicates, - columns?: Array + table: string, + predicates: dataSharePredicates.DataSharePredicates, + columns?: Array ): Promise; /** @@ -5113,10 +5113,10 @@ declare namespace relationalStore { * @since 12 */ getModifyTime( - table: string, - columnName: string, - primaryKeys: PRIKeyType[], - callback: AsyncCallback + table: string, + columnName: string, + primaryKeys: PRIKeyType[], + callback: AsyncCallback ): void; /** @@ -6276,10 +6276,10 @@ declare namespace relationalStore { * @since 12 */ setDistributedTables( - tables: Array, - type: DistributedType, - config: DistributedConfig, - callback: AsyncCallback + tables: Array, + type: DistributedType, + config: DistributedConfig, + callback: AsyncCallback ): void; /** @@ -6535,10 +6535,10 @@ declare namespace relationalStore { * @since 12 */ cloudSync( - mode: SyncMode, - tables: string[], - progress: Callback, - callback: AsyncCallback + mode: SyncMode, + tables: string[], + progress: Callback, + callback: AsyncCallback ): void; /** @@ -6604,10 +6604,10 @@ declare namespace relationalStore { * @since 12 */ cloudSync( - mode: SyncMode, - predicates: RdbPredicates, - progress: Callback, - callback: AsyncCallback + mode: SyncMode, + predicates: RdbPredicates, + progress: Callback, + callback: AsyncCallback ): void; /** @@ -6677,11 +6677,11 @@ declare namespace relationalStore { * @since 12 */ remoteQuery( - device: string, - table: string, - predicates: RdbPredicates, - columns: Array, - callback: AsyncCallback + device: string, + table: string, + predicates: RdbPredicates, + columns: Array, + callback: AsyncCallback ): void; /** @@ -6916,9 +6916,9 @@ declare namespace relationalStore { * @since 12 */ off( - event: 'dataChange', - type: SubscribeType, - observer?: Callback> | Callback> + event: 'dataChange', + type: SubscribeType, + observer?: Callback> | Callback> ): void; /** @@ -7253,7 +7253,7 @@ declare namespace relationalStore { /** * create a transaction instance and begin. * - * @param { TransactionOption } The option for creating transactions。 + * @param { TransactionOptions } The option for creating transactions. * @returns { Promise } The {@link Transaction} object if the operation is successful. * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800011 - Database corrupted. @@ -7261,21 +7261,25 @@ declare namespace relationalStore { * @throws { BusinessError } 14800015 - The database is busy. * @throws { BusinessError } 14800023 - SQLite: Access permission denied. * @throws { BusinessError } 14800024 - SQLite: The database file is locked. - * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. * @throws { BusinessError } 14800029 - SQLite: The database is full. * @throws { BusinessError } 14800030 - SQLite: Unable to open the database file. - * @throws { BusinessError } 14800032 - SQLite: Abort due to constraint violation. - * @throws { BusinessError } 14800033 - SQLite: Data type mismatch. - * @throws { BusinessError } 14800034 - SQLite: Library used incorrectly. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @crossplatform * @since 14 */ - createTransaction(option?: TransactionOption): Promise; + createTransaction(options?: TransactionOptions): Promise; } + /** + * Provides transactional methods for managing the relational database (RDB). + * + * @interface Transaction + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @crossplatform + * @since 14 + */ interface Transaction { /** * commit the transaction. @@ -7283,10 +7287,8 @@ declare namespace relationalStore { * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800011 - Database corrupted. * @throws { BusinessError } 14800014 - Already closed. - * @throws { BusinessError } 14800021 - SQLite: Generic error. * @throws { BusinessError } 14800023 - SQLite: Access permission denied. * @throws { BusinessError } 14800024 - SQLite: The database file is locked. - * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. @@ -7303,10 +7305,8 @@ declare namespace relationalStore { * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800011 - Database corrupted. * @throws { BusinessError } 14800014 - Already closed. - * @throws { BusinessError } 14800021 - SQLite: Generic error. * @throws { BusinessError } 14800023 - SQLite: Access permission denied. * @throws { BusinessError } 14800024 - SQLite: The database file is locked. - * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. @@ -7559,10 +7559,8 @@ declare namespace relationalStore { * @throws { BusinessError } 14800021 - SQLite: Generic error. * @throws { BusinessError } 14800023 - SQLite: Access permission denied. * @throws { BusinessError } 14800024 - SQLite: The database file is locked. - * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. - * @throws { BusinessError } 14800029 - SQLite: The database is full. * @throws { BusinessError } 14800047 - The WAL file size exceeds the default limit. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @crossplatform @@ -7587,7 +7585,6 @@ declare namespace relationalStore { * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. - * @throws { BusinessError } 14800029 - SQLite: The database is full. * @throws { BusinessError } 14800047 - The WAL file size exceeds the default limit. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @crossplatform @@ -7612,7 +7609,6 @@ declare namespace relationalStore { * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. - * @throws { BusinessError } 14800029 - SQLite: The database is full. * @throws { BusinessError } 14800047 - The WAL file size exceeds the default limit. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @crossplatform @@ -7637,7 +7633,6 @@ declare namespace relationalStore { * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. - * @throws { BusinessError } 14800029 - SQLite: The database is full. * @throws { BusinessError } 14800047 - The WAL file size exceeds the default limit. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @crossplatform diff --git a/relational_store/frameworks/js/napi/cloud_data/include/js_error_utils.h b/relational_store/frameworks/js/napi/cloud_data/include/js_error_utils.h index b2cb6d13..ca36f5df 100644 --- a/relational_store/frameworks/js/napi/cloud_data/include/js_error_utils.h +++ b/relational_store/frameworks/js/napi/cloud_data/include/js_error_utils.h @@ -33,6 +33,8 @@ struct JsErrorCode { const char *message = nullptr; }; + + const std::optional GetJsErrorCode(int32_t errorCode); Status GenerateNapiError(int32_t status, int32_t &errCode, std::string &errMessage); void ThrowNapiError(napi_env env, int32_t errCode, const std::string &errMessage); diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_context.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_context.h index 844150a2..5ffd6585 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_context.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_context.h @@ -17,6 +17,7 @@ #define NAPI_RDB_CONTEXT_H #include "napi_async_call.h" +#include "napi_rdb_js_utils.h" #include "napi_rdb_predicates.h" #include "transaction.h" #include "values_buckets.h" @@ -84,7 +85,7 @@ struct RdbStoreContext : public RdbStoreContextBase { }; struct CreateTransactionContext : public RdbStoreContextBase { - int32_t transactionType = 0; + AppDataMgrJsKit::JSUtils::TransactionOptions transactionOptions; std::shared_ptr transaction; }; } // namespace RelationalStoreJsKit diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h index 4ecc0ab4..d9bbadfc 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h @@ -75,6 +75,10 @@ struct ContextParam { bool isStageMode = true; }; +struct TransactionOptions { + int32_t transactionType = 0; +}; + template<> int32_t Convert2Value(napi_env env, napi_value input, Asset &output); @@ -93,6 +97,9 @@ int32_t Convert2Value(napi_env env, napi_value jsValue, CryptoParam &cryptoParam template<> int32_t Convert2Value(napi_env env, napi_value jsValue, RdbConfig &rdbConfig); +template<> +int32_t Convert2Value(napi_env env, napi_value jsValue, TransactionOptions &transactionOptions); + template<> int32_t Convert2Value(napi_env env, napi_value jsValue, ContextParam &context); diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_error.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_error.cpp index 1fbf4a56..8ad6b20a 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_error.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_error.cpp @@ -54,6 +54,18 @@ static constexpr JsErrorCode JS_ERROR_CODE_MSGS[] = { { NativeRdb::E_NOT_SUPPORT, 801, "Capability not support." }, }; +static constexpr bool IsIncreasing() +{ + for (size_t i = 1; i < sizeof(JS_ERROR_CODE_MSGS) / sizeof(JsErrorCode); i++) { + if (JS_ERROR_CODE_MSGS[i].status <= JS_ERROR_CODE_MSGS[i - 1].status) { + return false; + } + } + return true; +} + +static_assert(IsIncreasing()); + const std::optional GetJsErrorCode(int32_t errorCode) { auto jsErrorCode = JsErrorCode{ errorCode, -1, "" }; diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp index 9b83fee9..2e2fd8eb 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp @@ -26,6 +26,7 @@ #include "rdb_sql_utils.h" #include "rdb_types.h" #include "result_set.h" +#include "transaction.h" #define NAPI_CALL_RETURN_ERR(theCall, retVal) \ do { \ @@ -383,6 +384,14 @@ int32_t Convert2Value(napi_env env, napi_value jsValue, RdbConfig &rdbConfig) return napi_ok; } +template<> +int32_t Convert2Value(napi_env env, napi_value jsValue, TransactionOptions &transactionOptions) +{ + int32_t status = GetNamedProperty(env, jsValue, "transactionType", transactionOptions.transactionType, true); + ASSERT(OK == status, "get transactionType failed.", napi_invalid_arg); + return napi_ok; +} + int32_t GetCurrentAbilityParam(napi_env env, napi_value jsValue, ContextParam ¶m) { std::shared_ptr context = JSAbility::GetCurrentAbility(env, jsValue); diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp index 53880dac..455295fa 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp @@ -642,15 +642,15 @@ napi_value RdbStoreProxy::Insert(napi_env env, napi_callback_info info) return ASYNC_CALL(env, context); } -int ParseTransactionType( +int ParseTransactionOptions( const napi_env &env, size_t argc, napi_value *argv, std::shared_ptr context) { - context->transactionType = Transaction::DEFERRED; + context->transactionOptions.transactionType = Transaction::DEFERRED; if (argc > 0 && !JSUtils::IsNull(env, argv[0])) { - auto status = JSUtils::Convert2ValueExt(env, argv[0], context->transactionType); - bool checked = status == napi_ok && context->transactionType >= Transaction::DEFERRED && - context->transactionType <= Transaction::EXCLUSIVE; - CHECK_RETURN_SET(checked, std::make_shared("type", "a TransactionType")); + auto code = JSUtils::Convert2Value(env, argv[0], context->transactionOptions); + bool isValid = context->transactionOptions.transactionType >= Transaction::DEFERRED && + context->transactionOptions.transactionType <= Transaction::EXCLUSIVE; + CHECK_RETURN_SET(code == napi_ok && isValid, std::make_shared("options", "a transactionOptions")); } return OK; } @@ -2177,12 +2177,13 @@ napi_value RdbStoreProxy::CreateTransaction(napi_env env, napi_callback_info inf auto context = std::make_shared(); auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { CHECK_RETURN(OK == ParserThis(env, self, context)); - CHECK_RETURN(OK == ParseTransactionType(env, argc, argv, context)); + CHECK_RETURN(OK == ParseTransactionOptions(env, argc, argv, context)); }; auto exec = [context]() -> int { CHECK_RETURN_ERR(context->rdbStore != nullptr); int32_t code = E_ERROR; - std::tie(code, context->transaction) = context->StealRdbStore()->CreateTransaction(context->transactionType); + std::tie(code, context->transaction) = + context->StealRdbStore()->CreateTransaction(context->transactionOptions.transactionType); if (code != E_OK) { context->transaction = nullptr; return code; diff --git a/relational_store/frameworks/native/dfx/include/rdb_fault_hiview_reporter.h b/relational_store/frameworks/native/dfx/include/rdb_fault_hiview_reporter.h index e6582f89..f572251a 100644 --- a/relational_store/frameworks/native/dfx/include/rdb_fault_hiview_reporter.h +++ b/relational_store/frameworks/native/dfx/include/rdb_fault_hiview_reporter.h @@ -53,11 +53,11 @@ public: static void ReportRestore(const RdbCorruptedEvent &eventInfo, bool repair = true); static std::string Format(const std::map &debugs, const std::string &header); static std::string FormatBrief(const std::map &debugs, const std::string &header); + static bool IsReportCorruptedFault(const std::string &dbPath); private: static void Update(RdbCorruptedEvent &eventInfo, const std::map &infos); static std::string GetFileStatInfo(const DebugInfo &debugInfo); - static bool IsReportCorruptedFault(const std::string &dbPath); static void CreateCorruptedFlag(const std::string &dbPath); static void DeleteCorruptedFlag(const std::string &dbPath); static std::string GetTimeWithMilliseconds(time_t sec, int64_t nsec); diff --git a/relational_store/frameworks/native/rdb/include/connection_pool.h b/relational_store/frameworks/native/rdb/include/connection_pool.h index 6a0d444d..df0ef137 100644 --- a/relational_store/frameworks/native/rdb/include/connection_pool.h +++ b/relational_store/frameworks/native/rdb/include/connection_pool.h @@ -50,6 +50,8 @@ public: std::pair AcquireAll(int32_t time); std::pair DisableWal(); int32_t EnableWal(); + int32_t Dump(bool isWriter, const char *header); + int RestartReaders(); int ConfigLocale(const std::string &localeStr); int ChangeDbFileForRestore(const std::string &newPath, const std::string &backupPath, @@ -76,7 +78,7 @@ private: std::shared_ptr GetConnect(); int64_t GetUsingTime() const; bool IsWriter() const; - int32_t Unused(bool inTrans); + int32_t Unused(int32_t count); }; struct Container { @@ -109,7 +111,7 @@ private: int32_t Drop(std::shared_ptr node); int32_t Clear(); bool IsFull(); - int32_t Dump(const char *header, bool inTrans); + int32_t Dump(const char *header, int32_t count); private: int32_t ExtendNode(); diff --git a/relational_store/frameworks/native/rdb/include/grd_api_manager.h b/relational_store/frameworks/native/rdb/include/grd_api_manager.h index 8e6fed29..6f6d9897 100644 --- a/relational_store/frameworks/native/rdb/include/grd_api_manager.h +++ b/relational_store/frameworks/native/rdb/include/grd_api_manager.h @@ -26,34 +26,38 @@ typedef int32_t (*DBOpen)(const char *dbPath, const char *configStr, uint32_t fl typedef int32_t (*DBClose)(GRD_DB *db, uint32_t flags); typedef int32_t (*DBRepair)(const char *dbPath, const char *configStr); -typedef int (*DBSqlPrepare)(GRD_DB *db, const char *str, uint32_t strLen, GRD_SqlStmt **stmt, const char **unusedStr); -typedef int (*DBSqlReset)(GRD_SqlStmt *stmt); -typedef int (*DBSqlFinalize)(GRD_SqlStmt *stmt); -typedef int (*DBSqlBindBlob)(GRD_SqlStmt *stmt, uint32_t idx, const void *val, int32_t len, void (*freeFunc)(void *)); -typedef int (*DBSqlBindText)(GRD_SqlStmt *stmt, uint32_t idx, const void *val, int32_t len, void (*freeFunc)(void *)); -typedef int (*DBSqlBindInt)(GRD_SqlStmt *stmt, uint32_t idx, int32_t val); -typedef int (*DBSqlBindInt64)(GRD_SqlStmt *stmt, uint32_t idx, int64_t val); -typedef int (*DBSqlBindDouble)(GRD_SqlStmt *stmt, uint32_t idx, double val); -typedef int (*DBSqlBindNull)(GRD_SqlStmt *stmt, uint32_t idx); -typedef int (*DBSqlBindFloatVector)( +typedef int32_t (*DBSqlPrepare)( + GRD_DB *db, const char *str, uint32_t strLen, GRD_SqlStmt **stmt, const char **unusedStr); +typedef int32_t (*DBSqlReset)(GRD_SqlStmt *stmt); +typedef int32_t (*DBSqlFinalize)(GRD_SqlStmt *stmt); +typedef int32_t (*DBSqlBindBlob)( + GRD_SqlStmt *stmt, uint32_t idx, const void *val, int32_t len, void (*freeFunc)(void *)); +typedef int32_t (*DBSqlBindText)( + GRD_SqlStmt *stmt, uint32_t idx, const void *val, int32_t len, void (*freeFunc)(void *)); +typedef int32_t (*DBSqlBindInt)(GRD_SqlStmt *stmt, uint32_t idx, int32_t val); +typedef int32_t (*DBSqlBindInt64)(GRD_SqlStmt *stmt, uint32_t idx, int64_t val); +typedef int32_t (*DBSqlBindDouble)(GRD_SqlStmt *stmt, uint32_t idx, double val); +typedef int32_t (*DBSqlBindNull)(GRD_SqlStmt *stmt, uint32_t idx); +typedef int32_t (*DBSqlBindFloatVector)( GRD_SqlStmt *stmt, uint32_t idx, const float *val, uint32_t dim, void (*freeFunc)(void *)); -typedef int (*DBSqlStep)(GRD_SqlStmt *stmt); +typedef int32_t (*DBSqlStep)(GRD_SqlStmt *stmt); typedef uint32_t (*DBSqlColCnt)(GRD_SqlStmt *stmt); typedef GRD_DbDataTypeE (*DBSqlColType)(GRD_SqlStmt *stmt, uint32_t idx); -typedef int (*DBSqlColBytes)(GRD_SqlStmt *stmt, uint32_t idx); +typedef uint32_t (*DBSqlColBytes)(GRD_SqlStmt *stmt, uint32_t idx); typedef char *(*DBSqlColName)(GRD_SqlStmt *stmt, uint32_t idx); typedef GRD_DbValueT (*DBSqlColValue)(GRD_SqlStmt *stmt, uint32_t idx); -typedef uint8_t *(*DBSqlColBlob)(GRD_SqlStmt *stmt, uint32_t idx); -typedef char *(*DBSqlColText)(GRD_SqlStmt *stmt, uint32_t idx); -typedef int (*DBSqlColInt)(GRD_SqlStmt *stmt, uint32_t idx); -typedef uint64_t (*DBSqlColInt64)(GRD_SqlStmt *stmt, uint32_t idx); +typedef const void *(*DBSqlColBlob)(GRD_SqlStmt *stmt, uint32_t idx); +typedef const char *(*DBSqlColText)(GRD_SqlStmt *stmt, uint32_t idx); +typedef int32_t (*DBSqlColInt)(GRD_SqlStmt *stmt, uint32_t idx); +typedef int64_t (*DBSqlColInt64)(GRD_SqlStmt *stmt, uint32_t idx); typedef double (*DBSqlColDouble)(GRD_SqlStmt *stmt, uint32_t idx); typedef const float *(*DBSqlColumnFloatVector)(GRD_SqlStmt *stmt, uint32_t idx, uint32_t *dim); -typedef int (*DBBackup) (GRD_DB *db, const char *backupDbFile, uint8_t *encryptedKey, uint32_t encryptedKeyLen); -typedef int (*DBRestore) (GRD_DB *db, const char *backupDbFile, uint8_t *encryptedKey, uint32_t encryptedKeyLen); +typedef int32_t (*DBBackup) (GRD_DB *db, const char *backupDbFile, GRD_CipherInfoT *cipherInfo); +typedef int32_t (*DBRestore) (GRD_DB *db, const char *backupDbFile, GRD_CipherInfoT *cipherInfo); +typedef int32_t (*DBReKey) (const char *dbFile, const char *configStr, GRD_CipherInfoT *cipherInfo); typedef GRD_DbValueT (*DBGetConfig) (GRD_DB *db, GRD_ConfigTypeE type); -typedef int (*DBSetConfig) (GRD_DB *db, GRD_ConfigTypeE type, GRD_DbValueT value); +typedef int32_t (*DBSetConfig) (GRD_DB *db, GRD_ConfigTypeE type, GRD_DbValueT value); struct GRD_APIInfo { DBOpen DBOpenApi = nullptr; @@ -83,6 +87,7 @@ struct GRD_APIInfo { DBSqlColumnFloatVector DBSqlColumnFloatVector = nullptr; DBBackup DBBackupApi = nullptr; DBRestore DBRestoreApi = nullptr; + DBReKey DBReKeyApi = nullptr; DBGetConfig DBGetConfigApi = nullptr; DBSetConfig DBSetConfigApi = nullptr; }; diff --git a/relational_store/frameworks/native/rdb/include/grd_error.h b/relational_store/frameworks/native/rdb/include/grd_error.h index 9505e5a5..436031e9 100644 --- a/relational_store/frameworks/native/rdb/include/grd_error.h +++ b/relational_store/frameworks/native/rdb/include/grd_error.h @@ -40,7 +40,13 @@ extern "C" { #define GRD_FAILED_MEMORY_ALLOCATE (-13000) #define GRD_FAILED_MEMORY_RELEASE (-14000) #define GRD_DATA_CONFLICT (-16000) +#define GRD_DATA_MISMATCH (-17000) #define GRD_NOT_AVAILABLE (-19000) +#define GRD_ACTIVE_TRANSACTION (-20000) +#define GRD_UNIQUE_VIOLATION (-21000) +#define GRD_DUPLICATE_TABLE (-22000) +#define GRD_UNDEFINED_TABLE (-23000) +#define GRD_INVALID_BIND_VALUE (-36000) #define GRD_INVALID_FORMAT (-37000) #define GRD_REBUILD_DATABASE (-38000) #define GRD_TIME_OUT (-39000) @@ -48,10 +54,15 @@ extern "C" { #define GRD_DISK_SPACE_FULL (-41000) #define GRD_CRC_CHECK_DISABLED (-42000) #define GRD_PERMISSION_DENIED (-43000) +#define GRD_SYNC_PREREQUISITES_ABNORMAL (-44000) #define GRD_DATA_CORRUPTED (-45000) +#define GRD_DB_BUSY (-46000) +#define GRD_CALC_MODE_SET_PERMISSION_DENIED (-47000) // not support #define GRD_JSON_OPERATION_NOT_SUPPORT (-5001001) +#define GRD_MODEL_NOT_SUPPORT (-5001002) +#define GRD_FEATURE_NOT_SUPPORTED (-5001003) // Exceed limit #define GRD_JSON_LEN_LIMIT (-5002001) @@ -65,6 +76,11 @@ extern "C" { #define GRD_INVALID_PROJECTION_FIELD (-5003006) #define GRD_INVALID_PROJECTION_VALUE (-5003007) #define GRD_ARRAY_INDEX_NOT_FOUND (-5003008) +#define GRD_NAME_TOO_LONG (-5003025) +#define GRD_INVALID_TABLE_DEFINITION (-5003026) +#define GRD_WRONG_STMT_OBJECT (-5003027) +#define GRD_SEMANTIC_ERROR (-5003028) +#define GRD_SYNTAX_ERROR (-5003029) // System err #define GRD_JSON_LIB_HANDLE_FAILED (-5004001) @@ -82,10 +98,20 @@ extern "C" { // Cursor or ResultSet not available #define GRD_RESULT_SET_NOT_AVAILABLE (-5019001) +// violation +#define GRD_PRIMARY_KEY_VIOLATION (-5021001) +#define GRD_RESTRICT_VIOLATION (-5021002) +#define GRD_CONSTRAINT_CHECK_VIOLATION (-5021003) + // Invalid format #define GRD_INVALID_JSON_FORMAT (-5037001) #define GRD_INVALID_KEY_FORMAT (-5037002) #define GRD_INVALID_COLLECTION_NAME (-5037003) + +#define GRD_CIPHER_ERROR (-48000) +#define GRD_PASSWORD_NEED_REKEY (-48001) +#define GRD_PASSWORD_UNMATCHED (-48002) + #ifdef __cplusplus } #endif // __cplusplus diff --git a/relational_store/frameworks/native/rdb/include/grd_type_export.h b/relational_store/frameworks/native/rdb/include/grd_type_export.h index 80ad78a0..9d3632ae 100644 --- a/relational_store/frameworks/native/rdb/include/grd_type_export.h +++ b/relational_store/frameworks/native/rdb/include/grd_type_export.h @@ -73,6 +73,10 @@ typedef struct GRD_DbValueT { } value; } GRD_DbValueT; +typedef struct GRD_CipherInfo { + const char *hexPassword; +} GRD_CipherInfoT; + typedef struct GRD_DB GRD_DB; #ifdef __cplusplus diff --git a/relational_store/frameworks/native/rdb/include/rd_connection.h b/relational_store/frameworks/native/rdb/include/rd_connection.h index 26e16523..c58dc51d 100644 --- a/relational_store/frameworks/native/rdb/include/rd_connection.h +++ b/relational_store/frameworks/native/rdb/include/rd_connection.h @@ -63,8 +63,8 @@ public: private: static constexpr int MAX_VARIABLE_NUM = 500; static constexpr const char *GRD_OPEN_CONFIG_STR = - "{\"pageSize\":8, \"crcCheckEnable\":0, \"redoFlushByTrx\":1, \"bufferPoolSize\":10240," - "\"sharedModeEnable\":1, \"metaInfoBak\":1, \"maxConnNum\":500 }"; + "\"pageSize\":8, \"crcCheckEnable\":0, \"redoFlushByTrx\":1, \"bufferPoolSize\":10240," + "\"sharedModeEnable\":1, \"metaInfoBak\":1, \"maxConnNum\":500"; static constexpr uint32_t NO_ITER = 0; static constexpr uint32_t ITER_V1 = 5000; static constexpr uint32_t ITERS[] = {NO_ITER, ITER_V1}; @@ -73,10 +73,11 @@ private: static const int32_t regRepairer_; static const int32_t regDeleter_; + static std::string GetConfigStr(const std::vector &keys, bool isEncrypt); + std::string GetConfigStr(const std::vector &keys); int InnerOpen(const RdbStoreConfig &config); bool isWriter_ = false; GRD_DB *dbHandle_ = nullptr; - std::string configStr_ = GRD_OPEN_CONFIG_STR; const RdbStoreConfig config_; }; diff --git a/relational_store/frameworks/native/rdb/include/rd_utils.h b/relational_store/frameworks/native/rdb/include/rd_utils.h index 39cb6d14..7f471fe0 100644 --- a/relational_store/frameworks/native/rdb/include/rd_utils.h +++ b/relational_store/frameworks/native/rdb/include/rd_utils.h @@ -53,15 +53,18 @@ public: static char *RdSqlColName(GRD_SqlStmt *stmt, uint32_t idx); static GRD_DbValueT RdSqlColValue(GRD_SqlStmt *stmt, uint32_t idx); - static uint8_t *RdSqlColBlob(GRD_SqlStmt *stmt, uint32_t idx); - static char *RdSqlColText(GRD_SqlStmt *stmt, uint32_t idx); - static int RdSqlColInt(GRD_SqlStmt *stmt, uint32_t idx); - static uint64_t RdSqlColInt64(GRD_SqlStmt *stmt, uint32_t idx); + static const void *RdSqlColBlob(GRD_SqlStmt *stmt, uint32_t idx); + static const char *RdSqlColText(GRD_SqlStmt *stmt, uint32_t idx); + static int32_t RdSqlColInt(GRD_SqlStmt *stmt, uint32_t idx); + static int64_t RdSqlColInt64(GRD_SqlStmt *stmt, uint32_t idx); static double RdSqlColDouble(GRD_SqlStmt *stmt, uint32_t idx); static const float *RdSqlColumnFloatVector(GRD_SqlStmt *stmt, uint32_t idx, uint32_t *dim); - static int RdDbBackup(GRD_DB *db, const char *backupDbFile, uint8_t *encryptedKey, uint32_t encryptedKeyLen); - static int RdDbRestore(GRD_DB *db, const char *backupDbFile, uint8_t *encryptedKey, uint32_t encryptedKeyLen); + static void ClearAndZeroString(std::string &str); + static const char *GetEncryptKey(const std::vector &encryptedKey, char outBuff[], size_t outBufSize); + static int RdDbBackup(GRD_DB *db, const char *backupDbFile, const std::vector &encryptedKey); + static int RdDbRestore(GRD_DB *db, const char *backupDbFile, const std::vector &encryptedKey); + static int RdDbRekey(const char *dbFile, const char *configStr, const std::vector &encryptedKey); static int RdDbGetVersion(GRD_DB *db, GRD_ConfigTypeE type, int &version); static int RdDbSetVersion(GRD_DB *db, GRD_ConfigTypeE type, int version); diff --git a/relational_store/frameworks/native/rdb/include/transaction_impl.h b/relational_store/frameworks/native/rdb/include/transaction_impl.h index 5a4d6893..ce06928f 100644 --- a/relational_store/frameworks/native/rdb/include/transaction_impl.h +++ b/relational_store/frameworks/native/rdb/include/transaction_impl.h @@ -36,8 +36,12 @@ public: std::pair Insert(const std::string &table, const Row &row, Resolution resolution) override; std::pair BatchInsert(const std::string &table, const Rows &rows) override; std::pair BatchInsert(const std::string &table, const RefRows &rows) override; + std::pair Update(const std::string &table, const Row &row, const std::string &where, + const Values &args, Resolution resolution) override; std::pair Update(const Row &row, const AbsRdbPredicates &predicates, Resolution resolution) override; + std::pair Delete(const std::string &table, const std::string &whereClause, + const Values &args) override; std::pair Delete(const AbsRdbPredicates &predicates) override; std::shared_ptr QueryByStep(const std::string &sql, const Values &args) override; std::shared_ptr QueryByStep(const AbsRdbPredicates &predicates, const Fields &columns) override; diff --git a/relational_store/frameworks/native/rdb/src/connection_pool.cpp b/relational_store/frameworks/native/rdb/src/connection_pool.cpp index 05691362..bd4341a2 100644 --- a/relational_store/frameworks/native/rdb/src/connection_pool.cpp +++ b/relational_store/frameworks/native/rdb/src/connection_pool.cpp @@ -205,7 +205,8 @@ void ConnPool::SetInTransaction(bool isInTransaction) std::pair> ConnPool::CreateTransConn(bool limited) { if (transCount_ >= MAX_TRANS && limited) { - return { E_CON_OVER_LIMIT, nullptr }; + writers_.Dump("NO TRANS", transCount_ + isInTransaction_); + return { E_DATABASE_BUSY, nullptr }; } auto [errCode, node] = writers_.Create(); return { errCode, Convert2AutoConn(node, true) }; @@ -263,7 +264,7 @@ std::shared_ptr ConnPool::Acquire(bool isReadOnly, std::chrono::millisecon auto node = container->Acquire(ms); if (node == nullptr) { const char *header = (isReadOnly && maxReader_ != 0) ? "readers_" : "writers_"; - container->Dump(header, isInTransaction_); + container->Dump(header, transCount_ + isInTransaction_); return nullptr; } return Convert2AutoConn(node); @@ -277,7 +278,7 @@ SharedConn ConnPool::AcquireRef(bool isReadOnly, std::chrono::milliseconds ms) } auto node = writers_.Acquire(ms); if (node == nullptr) { - writers_.Dump("writers_", isInTransaction_); + writers_.Dump("writers_", transCount_ + isInTransaction_); return nullptr; } auto conn = node->connect_; @@ -297,11 +298,10 @@ void ConnPool::ReleaseNode(std::shared_ptr node, bool reuse) return; } - auto inTrans = (isInTransaction_ || transCount_ > 0); - auto errCode = node->Unused(inTrans); + auto transCount = transCount_ + isInTransaction_; + auto errCode = node->Unused(transCount); if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { - writers_.Dump("WAL writers_", inTrans); - readers_.Dump("WAL readers_", inTrans); + writers_.Dump("WAL writers_", transCount); } auto &container = node->IsWriter() ? writers_ : readers_; @@ -372,7 +372,7 @@ int ConnPool::ChangeDbFileForRestore(const std::string &newPath, const std::stri LOG_ERROR("Get null connection."); return retVal; } - retVal = connection->Restore(backupPath, {}, slaveStatus); + retVal = connection->Restore(backupPath, newKey, slaveStatus); if (retVal != E_OK) { LOG_ERROR("RdDbRestore error."); return retVal; @@ -449,6 +449,13 @@ int ConnPool::EnableWal() return errCode; } +int32_t ConnectionPool::Dump(bool isWriter, const char *header) +{ + Container *container = (isWriter || maxReader_ == 0) ? &writers_ : &readers_; + container->Dump(header, transCount_ + isInTransaction_); + return E_OK; +} + ConnPool::ConnNode::ConnNode(std::shared_ptr conn) : connect_(std::move(conn)) { } @@ -466,7 +473,7 @@ int64_t ConnPool::ConnNode::GetUsingTime() const return duration_cast(time).count(); } -int32_t ConnPool::ConnNode::Unused(bool inTrans) +int32_t ConnPool::ConnNode::Unused(int32_t count) { time_ = steady_clock::now(); if (connect_ == nullptr) { @@ -478,7 +485,7 @@ int32_t ConnPool::ConnNode::Unused(bool inTrans) tid_ = 0; } - if (inTrans) { + if (count > 0) { return E_OK; } auto timeout = time_ > (failedTime_ + minutes(CHECK_POINT_INTERVAL)) || time_ < failedTime_; @@ -751,11 +758,11 @@ bool ConnPool::Container::IsFull() return total_ == count_; } -int32_t ConnPool::Container::Dump(const char *header, bool inTrans) +int32_t ConnPool::Container::Dump(const char *header, int32_t count) { std::string info; std::vector> details; - std::string title = "B_M_T_C[" + std::to_string(inTrans) + "," + std::to_string(max_) + "," + + std::string title = "B_M_T_C[" + std::to_string(count) + "," + std::to_string(max_) + "," + std::to_string(total_) + "," + std::to_string(count_) + "]"; { std::unique_lock lock(mutex_); @@ -779,11 +786,11 @@ int32_t ConnPool::Container::Dump(const char *header, bool inTrans) .append(">"); // 256 represent that limit to info length if (info.size() > 256) { - LOG_WARN("%{public}s %{public}s: %{public}s", header, title.c_str(), info.c_str()); + LOG_WARN("%{public}s %{public}s:%{public}s", header, title.c_str(), info.c_str()); info.clear(); } } - LOG_WARN("%{public}s %{public}s: %{public}s", header, title.c_str(), info.c_str()); + LOG_WARN("%{public}s %{public}s:%{public}s", header, title.c_str(), info.c_str()); return 0; } } // namespace NativeRdb diff --git a/relational_store/frameworks/native/rdb/src/grd_api_manager.cpp b/relational_store/frameworks/native/rdb/src/grd_api_manager.cpp index bf7b70be..667c8bfb 100644 --- a/relational_store/frameworks/native/rdb/src/grd_api_manager.cpp +++ b/relational_store/frameworks/native/rdb/src/grd_api_manager.cpp @@ -58,6 +58,7 @@ void GRD_DBApiInitEnhance(GRD_APIInfo &GRD_DBApiInfo) GRD_DBApiInfo.DBSqlColumnFloatVector = (DBSqlColumnFloatVector)dlsym(g_library, "GRD_SqlColumnFloatVector"); GRD_DBApiInfo.DBBackupApi = (DBBackup)dlsym(g_library, "GRD_DBBackup"); GRD_DBApiInfo.DBRestoreApi = (DBRestore)dlsym(g_library, "GRD_DBRestore"); + GRD_DBApiInfo.DBReKeyApi = (DBReKey)dlsym(g_library, "GRD_DBRekey"); GRD_DBApiInfo.DBGetConfigApi = (DBGetConfig)dlsym(g_library, "GRD_GetConfig"); GRD_DBApiInfo.DBSetConfigApi = (DBSetConfig)dlsym(g_library, "GRD_SetConfig"); #endif diff --git a/relational_store/frameworks/native/rdb/src/rd_connection.cpp b/relational_store/frameworks/native/rdb/src/rd_connection.cpp index 779090e3..be1f69e5 100644 --- a/relational_store/frameworks/native/rdb/src/rd_connection.cpp +++ b/relational_store/frameworks/native/rdb/src/rd_connection.cpp @@ -15,10 +15,17 @@ #define LOG_TAG "RdConnection" #include "rd_connection.h" +#include +#include + #include "logger.h" +#include "grd_api_manager.h" #include "rd_statement.h" #include "rdb_errno.h" +#include "rdb_security_manager.h" #include "sqlite_global_config.h" +#include "sqlite_utils.h" + namespace OHOS { namespace NativeRdb { using namespace OHOS::Rdb; @@ -31,7 +38,11 @@ const int32_t RdConnection::regDeleter_ = Connection::RegisterDeleter(DB_VECTOR, std::pair> RdConnection::Create(const RdbStoreConfig& config, bool isWrite) { - std::pair> result; + std::pair> result = { E_ERROR, nullptr }; + if (!IsUsingArkData() || config.GetStorageMode() == StorageMode::MODE_MEMORY) { + result.first = E_NOT_SUPPORT; + return result; + } auto& [errCode, conn] = result; for (size_t i = 0; i < ITERS_COUNT; i++) { std::shared_ptr connection = std::make_shared(config, isWrite); @@ -56,7 +67,9 @@ int32_t RdConnection::Repair(const RdbStoreConfig& config) LOG_ERROR("Can not get db path."); return errCode; } - errCode = RdUtils::RdDbRepair(dbPath.c_str(), GRD_OPEN_CONFIG_STR); + std::vector key = config.GetEncryptKey(); + errCode = RdUtils::RdDbRepair(dbPath.c_str(), GetConfigStr(key, config.IsEncrypt()).c_str()); + key.assign(key.size(), 0); if (errCode != E_OK) { LOG_ERROR("Fail to repair db."); } @@ -101,6 +114,24 @@ RdConnection::~RdConnection() } } +std::string RdConnection::GetConfigStr(const std::vector &keys, bool isEncrypt) +{ + std::string config = "{"; + if (isEncrypt) { + const size_t keyBuffSize = keys.size() * 2 + 1; // 2 hex number can represent a uint8_t, 1 is for '/0' + char keyBuff[keyBuffSize]; + config += "\"isEncrypted\":1,"; + config += "\"hexPassword\":\""; + config += RdUtils::GetEncryptKey(keys, keyBuff, keyBuffSize); + config += "\","; + (void)memset_s(keyBuff, keyBuffSize, 0, keyBuffSize); + } + config += RdConnection::GRD_OPEN_CONFIG_STR; + config += "}"; + return config; +} + + int RdConnection::InnerOpen(const RdbStoreConfig &config) { std::string dbPath = ""; @@ -109,7 +140,31 @@ int RdConnection::InnerOpen(const RdbStoreConfig &config) LOG_ERROR("Can not get db path."); return errCode; } - errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr_.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_); + std::vector newKey = config.GetNewEncryptKey(); + if (!newKey.empty()) { + newKey.assign(newKey.size(), 0); + errCode = ReSetKey(config); + if (errCode != E_OK) { + LOG_ERROR("Can not reset key %{public}d.", errCode); + return errCode; + } + } + + std::vector key = config.GetEncryptKey(); + std::string configStr = GetConfigStr(key, config.IsEncrypt()); + errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_); + if (errCode == E_CHANGE_UNENCRYPTED_TO_ENCRYPTED) { + errCode = RdUtils::RdDbRekey(dbPath.c_str(), GetConfigStr({}, false).c_str(), key); + if (errCode != E_OK) { + key.assign(key.size(), 0); + RdUtils::ClearAndZeroString(configStr); + LOG_ERROR("Can not rekey caylay db %{public}d.", errCode); + return errCode; + } + errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_); + } + key.assign(key.size(), 0); + RdUtils::ClearAndZeroString(configStr); if (errCode != E_OK) { LOG_ERROR("Can not open rd db %{public}d.", errCode); return errCode; @@ -152,7 +207,30 @@ bool RdConnection::IsWriter() const int32_t RdConnection::ReSetKey(const RdbStoreConfig& config) { - return E_NOT_SUPPORT; + if (!IsWriter()) { + return E_OK; + } + std::string dbPath = ""; + int errCode = SqliteGlobalConfig::GetDbPath(config, dbPath); + if (errCode != E_OK) { + LOG_ERROR("Can not get db path."); + return errCode; + } + std::vector key = config.GetEncryptKey(); + std::vector newKey = config.GetNewEncryptKey(); + std::string configStr = GetConfigStr(key, config.IsEncrypt()); + errCode = RdUtils::RdDbRekey(dbPath.c_str(), configStr.c_str(), newKey); + RdUtils::ClearAndZeroString(configStr); + key.assign(key.size(), 0); + newKey.assign(newKey.size(), 0); + if (errCode != E_OK) { + LOG_ERROR("ReKey failed, err = %{public}d, errno = %{public}d", errCode, errno); + RdbSecurityManager::GetInstance().DelKeyFile( + config.GetPath(), RdbSecurityManager::KeyFileType::PUB_KEY_FILE_NEW_KEY); + return E_OK; + } + config.ChangeEncryptKey(); + return E_OK; } int32_t RdConnection::TryCheckPoint(bool timeout) @@ -210,21 +288,28 @@ int32_t RdConnection::Unsubscribe(const std::string& event, int32_t RdConnection::Backup(const std::string &databasePath, const std::vector &destEncryptKey, bool isAsync, SlaveStatus &slaveStatus) { - uint32_t size = destEncryptKey.size(); - if (size != 0) { - return RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), const_cast(&destEncryptKey[0]), size); + if (!destEncryptKey.empty() && !config_.IsEncrypt()) { + return RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), destEncryptKey); + } + if (config_.IsEncrypt()) { + std::vector key = config_.GetEncryptKey(); + int32_t ret = RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), key); + key.assign(key.size(), 0); + return ret; } - return RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), nullptr, 0); + return RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), {}); } int32_t RdConnection::Restore(const std::string &databasePath, const std::vector &destEncryptKey, SlaveStatus &slaveStatus) { - uint32_t size = destEncryptKey.size(); - if (size != 0) { - return RdUtils::RdDbRestore(dbHandle_, databasePath.c_str(), const_cast(&destEncryptKey[0]), size); + if (destEncryptKey.empty()) { + std::vector key = config_.GetEncryptKey(); + int32_t ret = RdUtils::RdDbRestore(dbHandle_, databasePath.c_str(), key); + key.assign(key.size(), 0); + return ret; } - return RdUtils::RdDbRestore(dbHandle_, databasePath.c_str(), nullptr, 0); + return RdUtils::RdDbRestore(dbHandle_, databasePath.c_str(), destEncryptKey); } ExchangeStrategy RdConnection::GenerateExchangeStrategy(const SlaveStatus &status) diff --git a/relational_store/frameworks/native/rdb/src/rd_utils.cpp b/relational_store/frameworks/native/rdb/src/rd_utils.cpp index 7acdf1af..6a5042b2 100644 --- a/relational_store/frameworks/native/rdb/src/rd_utils.cpp +++ b/relational_store/frameworks/native/rdb/src/rd_utils.cpp @@ -16,7 +16,11 @@ #define LOG_TAG "RdUtils" #include "rd_utils.h" +#include +#include #include +#include +#include #include "grd_error.h" #include "grd_api_manager.h" @@ -36,10 +40,43 @@ struct GrdErrnoPair { const GrdErrnoPair GRD_ERRNO_MAP[] = { { GRD_OK, E_OK }, + { GRD_REBUILD_DATABASE, E_OK}, { GRD_NO_DATA, E_NO_MORE_ROWS }, - { GRD_INNER_ERR, E_ERROR }, { GRD_DATA_CORRUPTED, E_SQLITE_CORRUPT }, - { GRD_INVALID_FILE_FORMAT, E_SQLITE_CORRUPT }, + { GRD_INVALID_FILE_FORMAT, E_SQLITE_CORRUPT }, + { GRD_PRIMARY_KEY_VIOLATION, E_SQLITE_CONSTRAINT}, + { GRD_RESTRICT_VIOLATION, E_SQLITE_CONSTRAINT}, + { GRD_CONSTRAINT_CHECK_VIOLATION, E_SQLITE_CONSTRAINT}, + { GRD_NOT_SUPPORT, E_NOT_SUPPORT }, + { GRD_OVER_LIMIT, E_SQLITE_CONSTRAINT }, + { GRD_INVALID_ARGS, E_INVALID_ARGS }, + { GRD_FAILED_FILE_OPERATION, E_SQLITE_IOERR }, + { GRD_INSUFFICIENT_SPACE, E_SQLITE_FULL }, + { GRD_RESOURCE_BUSY, E_DATABASE_BUSY }, + { GRD_DB_BUSY, E_DATABASE_BUSY }, + { GRD_FAILED_MEMORY_ALLOCATE, E_SQLITE_NOMEM }, + { GRD_CRC_CHECK_DISABLED, E_INVALID_ARGS }, + { GRD_DISK_SPACE_FULL, E_SQLITE_FULL }, + + { GRD_PERMISSION_DENIED, E_SQLITE_PERM }, + { GRD_PASSWORD_UNMATCHED, E_SQLITE_CANTOPEN }, + { GRD_PASSWORD_NEED_REKEY, E_CHANGE_UNENCRYPTED_TO_ENCRYPTED }, + + { GRD_NAME_TOO_LONG, E_SQLITE_CONSTRAINT}, + { GRD_INVALID_TABLE_DEFINITION, E_SQLITE_SCHEMA}, + { GRD_SEMANTIC_ERROR, E_NOT_SUPPORT_THE_SQL}, + { GRD_SYNTAX_ERROR, E_NOT_SUPPORT_THE_SQL}, + { GRD_DATA_MISMATCH, E_SQLITE_MISMATCH}, + { GRD_WRONG_STMT_OBJECT, E_INVALID_OBJECT_TYPE}, + { GRD_DATA_CONFLICT, E_INVALID_CONFLICT_FLAG }, + + { GRD_INNER_ERR, E_ERROR }, + { GRD_FAILED_MEMORY_RELEASE, E_ERROR }, + { GRD_NOT_AVAILABLE, E_ERROR }, + { GRD_INVALID_FORMAT, E_ERROR }, + { GRD_TIME_OUT, E_ERROR }, + { GRD_DB_INSTANCE_ABNORMAL, E_ERROR }, + { GRD_CIPHER_ERROR, E_ERROR }, }; int RdUtils::TransferGrdErrno(int err) @@ -87,7 +124,6 @@ int RdUtils::RdDbOpen(const char *dbPath, const char *configStr, uint32_t flags, int RdUtils::RdDbClose(GRD_DB *db, uint32_t flags) { - LOG_DEBUG("[RdUtils::RdDbClose]"); if (GRD_KVApiInfo.DBCloseApi == nullptr) { GRD_KVApiInfo = GetApiInfoInstance(); } @@ -351,7 +387,7 @@ GRD_DbValueT RdUtils::RdSqlColValue(GRD_SqlStmt *stmt, uint32_t idx) return GRD_KVApiInfo.DBSqlColValue(stmt, idx); } -uint8_t *RdUtils::RdSqlColBlob(GRD_SqlStmt *stmt, uint32_t idx) +const void *RdUtils::RdSqlColBlob(GRD_SqlStmt *stmt, uint32_t idx) { if (GRD_KVApiInfo.DBSqlColBlob == nullptr) { GRD_KVApiInfo = GetApiInfoInstance(); @@ -362,7 +398,7 @@ uint8_t *RdUtils::RdSqlColBlob(GRD_SqlStmt *stmt, uint32_t idx) return GRD_KVApiInfo.DBSqlColBlob(stmt, idx); } -char *RdUtils::RdSqlColText(GRD_SqlStmt *stmt, uint32_t idx) +const char *RdUtils::RdSqlColText(GRD_SqlStmt *stmt, uint32_t idx) { if (GRD_KVApiInfo.DBSqlColText == nullptr) { GRD_KVApiInfo = GetApiInfoInstance(); @@ -373,7 +409,7 @@ char *RdUtils::RdSqlColText(GRD_SqlStmt *stmt, uint32_t idx) return GRD_KVApiInfo.DBSqlColText(stmt, idx); } -int RdUtils::RdSqlColInt(GRD_SqlStmt *stmt, uint32_t idx) +int32_t RdUtils::RdSqlColInt(GRD_SqlStmt *stmt, uint32_t idx) { if (GRD_KVApiInfo.DBSqlColInt == nullptr) { GRD_KVApiInfo = GetApiInfoInstance(); @@ -384,7 +420,7 @@ int RdUtils::RdSqlColInt(GRD_SqlStmt *stmt, uint32_t idx) return GRD_KVApiInfo.DBSqlColInt(stmt, idx); } -uint64_t RdUtils::RdSqlColInt64(GRD_SqlStmt *stmt, uint32_t idx) +int64_t RdUtils::RdSqlColInt64(GRD_SqlStmt *stmt, uint32_t idx) { if (GRD_KVApiInfo.DBSqlColInt64 == nullptr) { GRD_KVApiInfo = GetApiInfoInstance(); @@ -417,7 +453,27 @@ const float *RdUtils::RdSqlColumnFloatVector(GRD_SqlStmt *stmt, uint32_t idx, ui return GRD_KVApiInfo.DBSqlColumnFloatVector(stmt, idx, dim); } -int RdUtils::RdDbBackup(GRD_DB *db, const char *backupDbFile, uint8_t *encryptedKey, uint32_t encryptedKeyLen) +void RdUtils::ClearAndZeroString(std::string &str) +{ + str.clear(); + std::fill(str.begin(), str.end(), char(0)); +} + +const char *RdUtils::GetEncryptKey(const std::vector &encryptedKey, char outBuff[], size_t outBufSize) +{ + char *buffer = nullptr; + for (size_t i = 0; i < encryptedKey.size(); i++) { + buffer = (char *)(outBuff + i * 2); // each uint8_t will convert to 2 hex char + // each uint8_t will convert to 2 hex char + errno_t err = snprintf_s(buffer, outBufSize - i * 2, outBufSize - i * 2, "%02x", encryptedKey[i]); + if (err < 0) { + return nullptr; + } + } + return outBuff; +} + +int RdUtils::RdDbBackup(GRD_DB *db, const char *backupDbFile, const std::vector &encryptedKey) { if (GRD_KVApiInfo.DBBackupApi == nullptr) { GRD_KVApiInfo = GetApiInfoInstance(); @@ -425,10 +481,20 @@ int RdUtils::RdDbBackup(GRD_DB *db, const char *backupDbFile, uint8_t *encrypted if (GRD_KVApiInfo.DBBackupApi == nullptr) { return E_NOT_SUPPORT; } - return TransferGrdErrno(GRD_KVApiInfo.DBBackupApi(db, backupDbFile, encryptedKey, encryptedKeyLen)); + const size_t keySize = encryptedKey.size() * 2 + 1; // 2 hex number can represent a uint8_t, 1 is for '/0' + char key[keySize]; + GRD_CipherInfoT info = { 0 }; + info.hexPassword = (encryptedKey.size() > 0) ? GetEncryptKey(encryptedKey, key, keySize) : nullptr; + int ret = TransferGrdErrno(GRD_KVApiInfo.DBBackupApi(db, backupDbFile, &info)); + errno_t err = memset_s(key, keySize, 0, keySize); + if (err != E_OK) { + LOG_ERROR("can not memset 0, size %{public}zu", keySize); + return E_ERROR; + } + return ret; } -int RdUtils::RdDbRestore(GRD_DB *db, const char *backupDbFile, uint8_t *encryptedKey, uint32_t encryptedKeyLen) +int RdUtils::RdDbRestore(GRD_DB *db, const char *backupDbFile, const std::vector &encryptedKey) { if (GRD_KVApiInfo.DBRestoreApi == nullptr) { GRD_KVApiInfo = GetApiInfoInstance(); @@ -436,9 +502,41 @@ int RdUtils::RdDbRestore(GRD_DB *db, const char *backupDbFile, uint8_t *encrypte if (GRD_KVApiInfo.DBRestoreApi == nullptr) { return E_NOT_SUPPORT; } - return TransferGrdErrno(GRD_KVApiInfo.DBRestoreApi(db, backupDbFile, encryptedKey, encryptedKeyLen)); + const size_t keySize = encryptedKey.size() * 2 + 1; // 2 hex number can represent a uint8_t, 1 is for '/0' + char key[keySize]; + GRD_CipherInfoT info = { 0 }; + info.hexPassword = (encryptedKey.size() > 0) ? GetEncryptKey(encryptedKey, key, keySize) : nullptr; + int ret = TransferGrdErrno(GRD_KVApiInfo.DBRestoreApi(db, backupDbFile, &info)); + errno_t err = memset_s(key, keySize, 0, keySize); + if (err != E_OK) { + LOG_ERROR("can not memset 0, size %{public}zu", keySize); + return E_ERROR; + } + return ret; +} + +int RdUtils::RdDbRekey(const char *dbFile, const char *configStr, const std::vector &encryptedKey) +{ + if (GRD_KVApiInfo.DBReKeyApi == nullptr) { + GRD_KVApiInfo = GetApiInfoInstance(); + } + if (GRD_KVApiInfo.DBReKeyApi == nullptr) { + return E_NOT_SUPPORT; + } + const size_t keySize = encryptedKey.size() * 2 + 1; // 2 hex number can represent a uint8_t, 1 is for '/0' + char key[keySize]; + GRD_CipherInfoT info = { 0 }; + info.hexPassword = (encryptedKey.size() > 0) ? GetEncryptKey(encryptedKey, key, keySize) : nullptr; + int ret = TransferGrdErrno(GRD_KVApiInfo.DBReKeyApi(dbFile, configStr, &info)); + errno_t err = memset_s(key, keySize, 0, keySize); + if (err != E_OK) { + LOG_ERROR("can not memset 0, size %{public}zu", keySize); + return E_ERROR; + } + return ret; } + int RdUtils::RdDbGetVersion(GRD_DB *db, GRD_ConfigTypeE type, int &version) { if (GRD_KVApiInfo.DBGetConfigApi == nullptr) { diff --git a/relational_store/frameworks/native/rdb/src/rdb_store.cpp b/relational_store/frameworks/native/rdb/src/rdb_store.cpp index d36c61ef..72136314 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store.cpp @@ -317,18 +317,20 @@ int RdbStore::ExecuteAndGetString(std::string &outValue, const std::string &sql, int RdbStore::ExecuteForLastInsertedRowId(int64_t &outValue, const std::string &sql, const Values &args) { - (void)outValue; - (void)sql; - (void)args; - return E_NOT_SUPPORT; + auto [errCode, value] = Execute(sql, args); + if (errCode == E_OK) { + (void)value.GetLong(outValue); + } + return errCode; } int RdbStore::ExecuteForChangedRowCount(int64_t &outValue, const std::string &sql, const Values &args) { - (void)outValue; - (void)sql; - (void)args; - return E_NOT_SUPPORT; + auto [errCode, value] = Execute(sql, args); + if (errCode == E_OK) { + (void)value.GetLong(outValue); + } + return errCode; } int RdbStore::Backup(const std::string &databasePath, const std::vector &encryptKey) diff --git a/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp b/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp index 1b00b3f5..0df7ad34 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp @@ -626,14 +626,8 @@ bool RdbStoreConfig::CryptoParam::IsValid() const return false; } - int32_t pageSize = cryptoPageSize; - if (pageSize < DB_MIN_CRYPTO_PAGE_SIZE || pageSize > DB_MAX_CRYPTO_PAGE_SIZE) { - return false; - } - if (!((pageSize != 0) && ((pageSize & (pageSize - 1)) == 0))) { - return false; - } - return true; + return (cryptoPageSize != 0) && ((cryptoPageSize & DB_INVALID_CRYPTO_PAGE_SIZE_MASK) == 0) && + (cryptoPageSize & (cryptoPageSize - 1)) == 0; } } // namespace OHOS::NativeRdb diff --git a/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp b/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp index 2d5d0408..14b81a2a 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp @@ -713,9 +713,10 @@ int RdbStoreImpl::UnregisterAutoSyncCallback(std::shared_ptr(); + if (delayNotifier_ != nullptr) { + return; } + delayNotifier_ = std::make_shared(); if (delayNotifier_ == nullptr) { LOG_ERROR("Init delay notifier failed."); return; @@ -1014,6 +1015,10 @@ std::pair RdbStoreImpl::BatchInsert(const std::string &table, cons } for (const auto &args : bindArgs) { auto errCode = statement->Execute(args); + if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { + connectionPool_->Dump(true, "BATCH"); + return { errCode, -1 }; + } if (errCode != E_OK) { LOG_ERROR("failed, errCode:%{public}d,args:%{public}zu,table:%{public}s,sql:%{public}s", errCode, bindArgs.size(), table.c_str(), sql.c_str()); @@ -1155,7 +1160,10 @@ int RdbStoreImpl::ExecuteSql(const std::string &sql, const Values &args) } errCode = statement->Execute(args); if (errCode != E_OK) { - LOG_ERROR("RDB_STORE Execute SQL ERROR."); + LOG_ERROR("failed,error:0x%{public}x sql:%{public}s.", errCode, sql.c_str()); + if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { + connectionPool_->Dump(true, "EXECUTE"); + } return errCode; } int sqlType = SqliteUtils::GetSqlStatementType(sql); @@ -1208,7 +1216,10 @@ std::pair RdbStoreImpl::Execute(const std::string &sql, co errCode = statement->Execute(args); if (errCode != E_OK) { - LOG_ERROR("execute sql failed, sql: %{public}s, error: %{public}d.", sql.c_str(), errCode); + LOG_ERROR("failed,error:0x%{public}x sql:%{public}s.", errCode, sql.c_str()); + if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { + connectionPool_->Dump(true, "EXECUTE"); + } return { errCode, object }; } @@ -1224,7 +1235,7 @@ std::pair RdbStoreImpl::HandleDifferentSqlTypes(std::share { int32_t errCode = E_OK; if (sqlType == SqliteUtils::STATEMENT_INSERT) { - int outValue = statement->Changes() > 0 ? statement->LastInsertRowId() : -1; + int64_t outValue = statement->Changes() > 0 ? statement->LastInsertRowId() : -1; return { errCode, ValueObject(outValue) }; } @@ -1269,10 +1280,10 @@ int RdbStoreImpl::ExecuteAndGetLong(int64_t &outValue, const std::string &sql, c } auto [err, object] = statement->ExecuteForValue(args); if (err != E_OK) { - LOG_ERROR("failed, sql %{public}s, ERROR is %{public}d.", sql.c_str(), errCode); + LOG_ERROR("failed, sql %{public}s, ERROR is %{public}d.", sql.c_str(), err); } outValue = object; - return errCode; + return err; } int RdbStoreImpl::ExecuteAndGetString(std::string &outValue, const std::string &sql, const Values &args) @@ -1306,6 +1317,9 @@ int RdbStoreImpl::ExecuteForLastInsertedRowId(int64_t &outValue, const std::stri auto beginExec = std::chrono::steady_clock::now(); errCode = statement->Execute(args); if (errCode != E_OK) { + if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { + connectionPool_->Dump(true, "INSERT"); + } return errCode; } auto beginResult = std::chrono::steady_clock::now(); @@ -1337,6 +1351,9 @@ int RdbStoreImpl::ExecuteForChangedRowCount(int64_t &outValue, const std::string } errCode = statement->Execute(args); if (errCode != E_OK) { + if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { + connectionPool_->Dump(true, "UPG DEL"); + } return errCode; } outValue = statement->Changes(); @@ -1346,7 +1363,6 @@ int RdbStoreImpl::ExecuteForChangedRowCount(int64_t &outValue, const std::string int RdbStoreImpl::GetDataBasePath(const std::string &databasePath, std::string &backupFilePath) { if (databasePath.empty()) { - LOG_ERROR("Empty databasePath."); return E_INVALID_FILE_PATH; } @@ -1470,16 +1486,12 @@ int RdbStoreImpl::InnerBackup(const std::string &databasePath, const std::vector } if (config_.GetDBType() == DB_VECTOR) { - if (config_.IsEncrypt()) { - return E_NOT_SUPPORT; - } - auto conn = connectionPool_->AcquireConnection(false); if (conn == nullptr) { return E_BASE; } - return conn->Backup(databasePath, {}, false, slaveStatus_); + return conn->Backup(databasePath, destEncryptKey, false, slaveStatus_); } if (config_.GetHaMode() != HAMode::SINGLE && SqliteUtils::IsSlaveDbName(databasePath)) { @@ -1554,7 +1566,7 @@ int RdbStoreImpl::SetDefaultEncryptSql( { auto errCode = statement->Prepare(sql); if (errCode != E_OK) { - LOG_ERROR("Prepare failed: %{public}s, %{public}d, %{public}d, %{public}d, %{public}d, %{public}d", + LOG_ERROR("Prepare failed: %{public}s, %{public}d, %{public}d, %{public}d, %{public}d, %{public}u", SqliteUtils::Anonymous(config.GetName()).c_str(), config.GetCryptoParam().iterNum, config.GetCryptoParam().encryptAlgo, config.GetCryptoParam().hmacAlgo, config.GetCryptoParam().kdfAlgo, config.GetCryptoParam().cryptoPageSize); @@ -1562,7 +1574,7 @@ int RdbStoreImpl::SetDefaultEncryptSql( } errCode = statement->Execute(); if (errCode != E_OK) { - LOG_ERROR("Execute failed: %{public}s, %{public}d, %{public}d, %{public}d, %{public}d, %{public}d", + LOG_ERROR("Execute failed: %{public}s, %{public}d, %{public}d, %{public}d, %{public}d, %{public}u", SqliteUtils::Anonymous(config.GetName()).c_str(), config.GetCryptoParam().iterNum, config.GetCryptoParam().encryptAlgo, config.GetCryptoParam().hmacAlgo, config.GetCryptoParam().kdfAlgo, config.GetCryptoParam().cryptoPageSize); @@ -1804,9 +1816,11 @@ int RdbStoreImpl::BeginTransaction() } errCode = statement->Execute(); if (errCode != E_OK) { + if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { + connectionPool_->Dump(true, "BEGIN"); + } LOG_ERROR("transaction id: %{public}zu, storeName: %{public}s, errCode: %{public}d", transactionId, SqliteUtils::Anonymous(name_).c_str(), errCode); - return errCode; } connectionPool_->SetInTransaction(true); @@ -1867,6 +1881,9 @@ int RdbStoreImpl::RollBack() } auto [errCode, statement] = GetStatement(transaction.GetRollbackStr()); if (statement == nullptr) { + if (errCode == E_DATABASE_BUSY) { + Reportor::Report(Reportor::Create(config_, errCode, "ErrorType: RollBusy")); + } // size + 1 means the number of transactions in process LOG_ERROR("transaction id: %{public}zu, storeName: %{public}s", transactionId + 1, SqliteUtils::Anonymous(name_).c_str()); @@ -1874,6 +1891,9 @@ int RdbStoreImpl::RollBack() } errCode = statement->Execute(); if (errCode != E_OK) { + if (errCode == E_SQLITE_BUSY || errCode == E_SQLITE_LOCKED) { + Reportor::Report(Reportor::Create(config_, errCode, "ErrorType: RollBusy")); + } LOG_ERROR("failed, id: %{public}zu, storeName: %{public}s, errCode: %{public}d", transactionId, SqliteUtils::Anonymous(name_).c_str(), errCode); return errCode; @@ -1959,8 +1979,8 @@ int RdbStoreImpl::Commit() } auto [errCode, statement] = GetStatement(sqlStr); if (statement == nullptr) { - if (errCode == E_DATABASE_BUSY || errCode == E_SQLITE_BUSY || E_SQLITE_LOCKED) { - Reportor::Report(Reportor::Create(config_, E_DATABASE_BUSY, "ErrorType: Busy")); + if (errCode == E_DATABASE_BUSY) { + Reportor::Report(Reportor::Create(config_, errCode, "ErrorType: CommitBusy")); } LOG_ERROR("id: %{public}zu, storeName: %{public}s, statement error", transactionId, SqliteUtils::Anonymous(name_).c_str()); @@ -1968,6 +1988,9 @@ int RdbStoreImpl::Commit() } errCode = statement->Execute(); if (errCode != E_OK) { + if (errCode == E_SQLITE_BUSY || errCode == E_SQLITE_LOCKED) { + Reportor::Report(Reportor::Create(config_, errCode, "ErrorType: CommitBusy")); + } LOG_ERROR("failed, id: %{public}zu, storeName: %{public}s, errCode: %{public}d", transactionId, SqliteUtils::Anonymous(name_).c_str(), errCode); return errCode; @@ -2159,15 +2182,18 @@ int RdbStoreImpl::Restore(const std::string &backupPath, const std::vectorDisable(syncerParam_); } #endif + bool corrupt = Reportor::IsReportCorruptedFault(path_); int errCode = connectionPool_->ChangeDbFileForRestore(path_, destPath, newKey, slaveStatus_); + keyFiles.Unlock(); #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) - NotifyDataChange(); SecurityPolicy::SetSecurityLabel(config_); if (service != nullptr) { service->Enable(syncerParam_); @@ -2187,11 +2214,12 @@ int RdbStoreImpl::Restore(const std::string &backupPath, const std::vectorAfterOpen(syncerParam); + NotifyDataChange(); } } #endif if (errCode == E_OK) { - Reportor::ReportRestore(Reportor::Create(config_, E_OK)); + Reportor::ReportRestore(Reportor::Create(config_, E_OK), corrupt); rebuild_ = RebuiltType::NONE; } if (!cloudTables_.empty()) { @@ -2312,6 +2340,9 @@ int32_t RdbStoreImpl::GetDbType() const std::pair> RdbStoreImpl::CreateTransaction(int32_t type) { + if (isReadOnly_) { + return { E_NOT_SUPPORT, nullptr }; + } auto [errCode, conn] = connectionPool_->CreateTransConn(); if (conn == nullptr) { return { errCode, nullptr }; @@ -2319,6 +2350,9 @@ std::pair> RdbStoreImpl::CreateTransaction std::shared_ptr trans; std::tie(errCode, trans) = Transaction::Create(type, conn, config_.GetName()); if (trans == nullptr) { + if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { + connectionPool_->Dump(true, "TRANS"); + } return { errCode, nullptr }; } diff --git a/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp b/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp index c1cb3497..923012d1 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp @@ -87,10 +87,6 @@ std::shared_ptr RdbStoreManager::GetStoreFromCache(const RdbStoreC std::shared_ptr RdbStoreManager::GetRdbStore( const RdbStoreConfig &config, int &errCode, int version, RdbOpenCallback &openCallback) { - if (config.IsVector() && config.GetStorageMode() == StorageMode::MODE_MEMORY) { - LOG_ERROR("GetRdbStore type not support memory mode."); - return nullptr; - } // TOD this lock should only work on storeCache_, add one more lock for connectionpool std::lock_guard lock(mutex_); auto path = config.GetRoleType() == VISITOR ? config.GetVisitorDir() : config.GetPath(); diff --git a/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp b/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp index e64a12e1..39b3c84a 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp @@ -522,7 +522,7 @@ int SqliteConnection::SetPageSize(const RdbStoreConfig &config) int SqliteConnection::SetEncryptAgo(const RdbStoreConfig &config) { if (!config.GetCryptoParam().IsValid()) { - LOG_ERROR("Invalid crypto param: %{public}s, %{public}d, %{public}d, %{public}d, %{public}d, %{public}d", + LOG_ERROR("Invalid crypto param: %{public}s, %{public}d, %{public}d, %{public}d, %{public}d, %{public}u", SqliteUtils::Anonymous(config.GetName()).c_str(), config.GetCryptoParam().iterNum, config.GetCryptoParam().encryptAlgo, config.GetCryptoParam().hmacAlgo, config.GetCryptoParam().kdfAlgo, config.GetCryptoParam().cryptoPageSize); diff --git a/relational_store/frameworks/native/rdb/src/transaction_impl.cpp b/relational_store/frameworks/native/rdb/src/transaction_impl.cpp index 3806db3b..ed818a95 100644 --- a/relational_store/frameworks/native/rdb/src/transaction_impl.cpp +++ b/relational_store/frameworks/native/rdb/src/transaction_impl.cpp @@ -196,6 +196,17 @@ std::pair TransactionImpl::BatchInsert(const std::string &table, c return store->BatchInsert(table, rows); } +std::pair TransactionImpl::Update(const std::string &table, const Row &row, const std::string &where, + const Values &args, Resolution resolution) +{ + auto store = GetStore(); + if (store == nullptr) { + LOG_ERROR("transaction already close"); + return { E_ALREADY_CLOSED, -1 }; + } + return store->Update(table, row, where, args, resolution); +} + std::pair TransactionImpl::Update(const Row &row, const AbsRdbPredicates &predicates, Resolution resolution) { @@ -208,6 +219,19 @@ std::pair TransactionImpl::Update(const Row &row, const AbsRdb resolution); } +std::pair TransactionImpl::Delete(const std::string &table, const std::string &whereClause, + const Values &args) +{ + auto store = GetStore(); + if (store == nullptr) { + LOG_ERROR("transaction already close"); + return { E_ALREADY_CLOSED, -1 }; + } + int deletedRows{}; + auto errorCode = store->Delete(deletedRows, table, whereClause, args); + return { errorCode, deletedRows }; +} + std::pair TransactionImpl::Delete(const AbsRdbPredicates &predicates) { auto store = GetStore(); diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h b/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h index a286a9da..df2b92e3 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h @@ -214,7 +214,7 @@ public: int32_t encryptAlgo = EncryptAlgo::AES_256_GCM; int32_t hmacAlgo = HmacAlgo::SHA256; int32_t kdfAlgo = KdfAlgo::KDF_SHA256; - int32_t cryptoPageSize = RdbStoreConfig::DB_DEFAULT_CRYPTO_PAGE_SIZE; + uint32_t cryptoPageSize = RdbStoreConfig::DB_DEFAULT_CRYPTO_PAGE_SIZE; mutable std::vector encryptKey_{}; API_EXPORT CryptoParam(); API_EXPORT ~CryptoParam(); @@ -244,17 +244,12 @@ public: /** * @brief The constant indicates the database default crypto page size. */ - static constexpr int DB_DEFAULT_CRYPTO_PAGE_SIZE = 1024; + static constexpr uint32_t DB_DEFAULT_CRYPTO_PAGE_SIZE = 1024; /** - * @brief The constant indicates the database minimum crypto page size. + * @brief The constant indicates the bit mask of the invalid range of crypto page size. */ - static constexpr int DB_MIN_CRYPTO_PAGE_SIZE = 1024; - - /** - * @brief The constant indicates the database maximum crypto page size. - */ - static constexpr int DB_MAX_CRYPTO_PAGE_SIZE = 65536; + static constexpr uint32_t DB_INVALID_CRYPTO_PAGE_SIZE_MASK = 0xFFFE03FF; /** * @brief Constructor. diff --git a/relational_store/interfaces/inner_api/rdb/include/transaction.h b/relational_store/interfaces/inner_api/rdb/include/transaction.h index c4dba75a..409ab828 100644 --- a/relational_store/interfaces/inner_api/rdb/include/transaction.h +++ b/relational_store/interfaces/inner_api/rdb/include/transaction.h @@ -112,6 +112,18 @@ public: */ virtual std::pair BatchInsert(const std::string &table, const RefRows &rows) = 0; + /** + * @brief Updates data in the database based on specified conditions. + * + * @param table Indicates the target table. + * @param row Indicates the row of data to be updated in the database. + * The key-value pairs are associated with column names of the database table. + * @param whereClause Indicates the where clause. + * @param args Indicates the where arguments. + */ + virtual std::pair Update(const std::string &table, const Row &row, const std::string &where = "", + const Values &args = {}, Resolution resolution = NO_ACTION) = 0; + /** * @brief Updates data in the database based on a a specified instance object of AbsRdbPredicates. * @@ -122,6 +134,16 @@ public: virtual std::pair Update(const Row &row, const AbsRdbPredicates &predicates, Resolution resolution = NO_ACTION) = 0; + /** + * @brief Deletes data from the database based on specified conditions. + * + * @param table Indicates the target table. + * @param whereClause Indicates the where clause. + * @param args Indicates the where arguments. + */ + virtual std::pair Delete(const std::string &table, const std::string &whereClause = "", + const Values &args = {}) = 0; + /** * @brief Deletes data from the database based on a specified instance object of AbsRdbPredicates. * diff --git a/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h b/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h index 630e6883..66b4b060 100644 --- a/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h +++ b/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h @@ -119,7 +119,7 @@ public: int32_t encryptAlgo = EncryptAlgo::AES_256_GCM; int32_t hmacAlgo = HmacAlgo::SHA256; int32_t kdfAlgo = KdfAlgo::KDF_SHA256; - int32_t cryptoPageSize = RdbStoreConfig::DB_DEFAULT_CRYPTO_PAGE_SIZE; + uint32_t cryptoPageSize = RdbStoreConfig::DB_DEFAULT_CRYPTO_PAGE_SIZE; mutable std::vector encryptKey_{}; CryptoParam(); ~CryptoParam(); @@ -129,9 +129,8 @@ public: static constexpr int DB_JOURNAL_SIZE = 1024 * 1024; /* default file size : 1M */ static constexpr char DB_DEFAULT_JOURNAL_MODE[] = "WAL"; static constexpr EncryptAlgo DB_DEFAULT_ENCRYPT_ALGO = AES_256_GCM; - static constexpr int DB_DEFAULT_CRYPTO_PAGE_SIZE = 1024; - static constexpr int DB_MIN_CRYPTO_PAGE_SIZE = 1024; - static constexpr int DB_MAX_CRYPTO_PAGE_SIZE = 65536; + static constexpr uint32_t DB_DEFAULT_CRYPTO_PAGE_SIZE = 1024; + static constexpr uint32_t DB_INVALID_CRYPTO_PAGE_SIZE_MASK = 0xFFFE03FF; RdbStoreConfig(const std::string &path, StorageMode storageMode = StorageMode::MODE_DISK, bool readOnly = false, const std::vector &encryptKey = std::vector(), const std::string &journalMode = DB_DEFAULT_JOURNAL_MODE, const std::string &syncMode = "", diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransInsertJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransInsertJsunit.test.js new file mode 100644 index 00000000..4326a934 --- /dev/null +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransInsertJsunit.test.js @@ -0,0 +1,945 @@ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * 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. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from 'deccjsunit/index' +import data_relationalStore from '@ohos.data.relationalStore' +import ability_featureAbility from '@ohos.ability.featureAbility' + +var context = ability_featureAbility.getContext() + +const TAG = "[RELATIONAL_STORE_TRANSACTION_JSKITS_TEST]" +const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY, " + + "name TEXT NOT NULL, " + "age INTEGER, " + "salary REAL, " + "blobType BLOB)"; + +const STORE_CONFIG = { + name: "TransactionTest.db", + securityLevel: data_relationalStore.SecurityLevel.S3, +} + +var rdbStore = undefined; + +describe('rdbStoreTransactionJsunitTest', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll') + rdbStore = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await rdbStore.executeSql(CREATE_TABLE_TEST, null); + }) + + beforeEach(async function () { + console.info(TAG + 'beforeEach') + + }) + + afterEach(async function () { + console.info(TAG + 'afterEach') + await rdbStore.executeSql("DELETE FROM test"); + }) + + afterAll(async function () { + console.info(TAG + 'afterAll') + rdbStore = null + await data_relationalStore.deleteRdbStore(context, "TransactionTest.db"); + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + + it('testRdbTransInsert0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsert0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsert0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsert0001 failed"); + } + + console.log(TAG + "************* testRdbTransInsert0001 end *************"); + done(); + }) + + it('testRdbTransInsert0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsert0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsert0002 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsert0002 failed"); + } + + console.log(TAG + "************* testRdbTransInsert0002 end *************"); + done(); + }) + + it('testRdbTransInsert0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsert0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsert0003 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsert0003 failed"); + } + + console.log(TAG + "************* testRdbTransInsert0003 end *************"); + done(); + }) + + it('testRdbTransInsert0011', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsert0011 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsert0011 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsert0011 failed"); + } + + console.log(TAG + "************* testRdbTransInsert0011 end *************"); + done(); + }) + + it('testRdbTransInsert0012', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsert0012 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsert0012 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsert0012 failed"); + } + + console.log(TAG + "************* testRdbTransInsert0012 end *************"); + done(); + }) + + it('testRdbTransInsert0013', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsert0013 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsert0013 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsert0013 failed"); + } + + console.log(TAG + "************* testRdbTransInsert0013 end *************"); + done(); + }) + + it('testRdbTransInsertSync0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsertSync0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = rdbTrans.insertSync("test", valueBucket); + expect(1).assertEqual(rowId); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsertSync0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsertSync0001 failed"); + } + + console.log(TAG + "************* testRdbTransInsertSync0001 end *************"); + done(); + }) + + it('testRdbTransInsertSync0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsertSync0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = rdbTrans.insertSync("test", valueBucket); + expect(1).assertEqual(rowId); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsertSync0002 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsertSync0002 failed"); + } + + console.log(TAG + "************* testRdbTransInsertSync0002 end *************"); + done(); + }) + + it('testRdbTransInsertSync0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsertSync0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = rdbTrans.insertSync("test", valueBucket); + expect(1).assertEqual(rowId); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsertSync0003 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsertSync0003 failed"); + } + + console.log(TAG + "************* testRdbTransInsertSync0003 end *************"); + done(); + }) + + it('testRdbTransInsertSync0011', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsertSync0011 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = rdbTrans.insertSync("test", valueBucket); + expect(1).assertEqual(rowId); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsertSync0011 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsertSync0011 failed"); + } + + console.log(TAG + "************* testRdbTransInsertSync0011 end *************"); + done(); + }) + + it('testRdbTransInsertSync0012', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsertSync0012 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = rdbTrans.insertSync("test", valueBucket); + expect(1).assertEqual(rowId); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsertSync0012 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsertSync0012 failed"); + } + + console.log(TAG + "************* testRdbTransInsertSync0012 end *************"); + done(); + }) + + it('testRdbTransInsertSync0013', 0, async (done) => { + console.log(TAG + "************* testRdbTransInsertSync0013 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = rdbTrans.insertSync("test", valueBucket); + expect(1).assertEqual(rowId); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransInsertSync0013 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransInsertSync0013 failed"); + } + + console.log(TAG + "************* testRdbTransInsertSync0013 end *************"); + done(); + }) + + it('testRdbTransBatchInsert0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsert0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = await rdbTrans.batchInsert("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsert0001 result count " + resultSet.rowCount); + expect(100).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsert0001 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsert0001 end *************"); + done(); + }) + + it('testRdbTransBatchInsert0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsert0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = await rdbTrans.batchInsert("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsert0002 result count " + resultSet.rowCount); + expect(100).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsert0002 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsert0002 end *************"); + done(); + }) + + it('testRdbTransBatchInsert0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsert0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = await rdbTrans.batchInsert("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsert0003 result count " + resultSet.rowCount); + expect(100).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsert0003 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsert0003 end *************"); + done(); + }) + + it('testRdbTransBatchInsert0011', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsert0011 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = await rdbTrans.batchInsert("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsert0011 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsert0011 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsert0011 end *************"); + done(); + }) + + it('testRdbTransBatchInsert0012', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsert0012 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = await rdbTrans.batchInsert("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsert0012 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsert0012 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsert0012 end *************"); + done(); + }) + + it('testRdbTransBatchInsert0013', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsert0013 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = await rdbTrans.batchInsert("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsert0013 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsert0013 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsert0013 end *************"); + done(); + }) + + it('testRdbTransBatchInsertSync0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsertSync0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = rdbTrans.batchInsertSync("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsertSync0001 result count " + resultSet.rowCount); + expect(100).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsertSync0001 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsertSync0001 end *************"); + done(); + }) + + it('testRdbTransBatchInsertSync0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsertSync0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = rdbTrans.batchInsertSync("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsertSync0002 result count " + resultSet.rowCount); + expect(100).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsertSync0002 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsertSync0002 end *************"); + done(); + }) + + it('testRdbTransBatchInsertSync0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsertSync0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = rdbTrans.batchInsertSync("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsertSync0003 result count " + resultSet.rowCount); + expect(100).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsertSync0003 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsertSync0003 end *************"); + done(); + }) + + it('testRdbTransBatchInsertSync0011', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsertSync0011 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = rdbTrans.batchInsertSync("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsertSync0011 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsertSync0011 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsertSync0011 end *************"); + done(); + }) + + it('testRdbTransBatchInsertSync0012', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsertSync0012 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = rdbTrans.batchInsertSync("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsertSync0012 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsertSync0012 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsertSync0012 end *************"); + done(); + }) + + it('testRdbTransBatchInsertSync0013', 0, async (done) => { + console.log(TAG + "************* testRdbTransBatchInsertSync0013 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBuckets = new Array(100).fill(0).map(() => { + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + return valueBucket; + }) + const rowCount = rdbTrans.batchInsertSync("test", valueBuckets); + expect(rowCount).assertEqual(100); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransBatchInsertSync0013 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransBatchInsertSync0013 failed"); + } + + console.log(TAG + "************* testRdbTransBatchInsertSync0013 end *************"); + done(); + }) + + it('testRdbTransUpdate0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdate0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbTrans.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + await rdbTrans.update({ age: 20 }, updatePredicates); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdate0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(20); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdate0001 failed"); + } + + console.log(TAG + "************* testRdbTransUpdate0001 end *************"); + done(); + }) + + it('testRdbTransUpdate0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdate0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbTrans.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + await rdbTrans.update({ age: 20 }, updatePredicates); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdate0002 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(20); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdate0002 failed"); + } + + console.log(TAG + "************* testRdbTransUpdate0002 end *************"); + done(); + }) + + it('testRdbTransUpdate0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdate0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbTrans.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + await rdbTrans.update({ age: 20 }, updatePredicates); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdate0003 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(20); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdate0003 failed"); + } + + console.log(TAG + "************* testRdbTransUpdate0003 end *************"); + done(); + }) + + console.log(TAG + "*************Unit Test End*************"); +}) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransJsunit.test.js new file mode 100644 index 00000000..4d150faa --- /dev/null +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransJsunit.test.js @@ -0,0 +1,1986 @@ +/* + * Copyright (C) 2024 Huawei Device Co., Ltd. + * 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. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from 'deccjsunit/index' +import data_relationalStore from '@ohos.data.relationalStore' +import ability_featureAbility from '@ohos.ability.featureAbility' + +var context = ability_featureAbility.getContext() + +const TAG = "[RELATIONAL_STORE_TRANSACTION_JSKITS_TEST]" +const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY, " + + "name TEXT NOT NULL, " + "age INTEGER, " + "salary REAL, " + "blobType BLOB)"; + +const STORE_CONFIG = { + name: "TransactionTest.db", + securityLevel: data_relationalStore.SecurityLevel.S3, +} + +var rdbStore = undefined; + +async function insertInThread(context, transType, insertCount = 1) { + const TAG = "[RELATIONAL_STORE_JS_KITS_TEST]" + let rdbTrans; + try { + rdbTrans = await rdbStore.createTransaction({ + transactionType: transType + }); + console.log(TAG + 'insertInThread after createTrans'); + + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(insertCount).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }); + const resultCount = await rdbTrans.batchInsert("test", valueBuckets); + await rdbTrans.commit(); + console.log(TAG + 'insertInThread after commit'); + return resultCount; + } catch (err) { + if (rdbTrans) { + rdbTrans.rollback(); + } + console.error(TAG + "************* testRdbTransInsert error thread insert *************"); + console.error(TAG + JSON.stringify(err)); + return err.code; + } +} + +async function queryInThread(context, transType, querySql) { + const TAG = "[RELATIONAL_STORE_JS_KITS_TEST]" + let rdbTrans; + try { + rdbTrans = await rdbStore.createTransaction({ + transactionType: transType + }); + + const resultSet = await rdbTrans.querySql(querySql); + const rowCount = resultSet.rowCount; + + await rdbTrans.commit(); + return rowCount; + } catch (err) { + if (rdbTrans) { + rdbTrans.rollback(); + } + console.error(TAG + "************* testRdbTransInsert error thread insert *************"); + console.error(TAG + JSON.stringify(err)); + return err.code; + } +} + +describe('rdbStoreTransactionJsunitTest', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll') + rdbStore = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await rdbStore.executeSql(CREATE_TABLE_TEST, null); + }) + + beforeEach(async function () { + console.info(TAG + 'beforeEach') + + }) + + afterEach(async function () { + console.info(TAG + 'afterEach') + await rdbStore.executeSql("DELETE FROM test"); + }) + + afterAll(async function () { + console.info(TAG + 'afterAll') + rdbStore = null + await data_relationalStore.deleteRdbStore(context, "TransactionTest.db"); + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + it('testRdbTransUpdate0011', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdate0011 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbStore.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + await rdbTrans.update({ age: 20 }, updatePredicates); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdate0011 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(18); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdate0011 failed"); + } + + console.log(TAG + "************* testRdbTransUpdate0011 end *************"); + done(); + }) + + it('testRdbTransUpdate0012', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdate0012 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbStore.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + await rdbTrans.update({ age: 20 }, updatePredicates); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdate0012 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(18); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdate0012 failed"); + } + + console.log(TAG + "************* testRdbTransUpdate0012 end *************"); + done(); + }) + + it('testRdbTransUpdate0013', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdate0013 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbStore.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + await rdbTrans.update({ age: 20 }, updatePredicates); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdate0013 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(18); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdate0013 failed"); + } + + console.log(TAG + "************* testRdbTransUpdate0013 end *************"); + done(); + }) + + it('testRdbTransUpdateSync0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdateSync0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbTrans.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + rdbTrans.updateSync({ age: 20 }, updatePredicates); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdateSync0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(20); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdateSync0001 failed"); + } + + console.log(TAG + "************* testRdbTransUpdateSync0001 end *************"); + done(); + }) + + it('testRdbTransUpdateSync0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdateSync0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbTrans.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + rdbTrans.updateSync({ age: 20 }, updatePredicates); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdateSync0002 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(20); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdateSync0002 failed"); + } + + console.log(TAG + "************* testRdbTransUpdateSync0002 end *************"); + done(); + }) + + it('testRdbTransUpdateSync0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdateSync0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbTrans.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + rdbTrans.updateSync({ age: 20 }, updatePredicates); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdateSync0003 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(20); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdateSync0003 failed"); + } + + console.log(TAG + "************* testRdbTransUpdateSync0003 end *************"); + done(); + }) + + it('testRdbTransUpdateSync0011', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdateSync0011 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbStore.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + rdbTrans.updateSync({ age: 20 }, updatePredicates); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdateSync0011 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(18); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdateSync0011 failed"); + } + + console.log(TAG + "************* testRdbTransUpdateSync0011 end *************"); + done(); + }) + + it('testRdbTransUpdateSync0012', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdateSync0012 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbStore.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + rdbTrans.updateSync({ age: 20 }, updatePredicates); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdateSync0012 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(18); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdateSync0012 failed"); + } + + console.log(TAG + "************* testRdbTransUpdateSync0012 end *************"); + done(); + }) + + it('testRdbTransUpdateSync0013', 0, async (done) => { + console.log(TAG + "************* testRdbTransUpdateSync0013 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + const rowId = await rdbStore.insert("test", valueBucket); + expect(rowId).assertEqual(1); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + rdbTrans.updateSync({ age: 20 }, updatePredicates); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransUpdateSync0013 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + const rowData = resultSet.getRow(); + expect(rowData['age']).assertEqual(18); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransUpdateSync0013 failed"); + } + + console.log(TAG + "************* testRdbTransUpdateSync0013 end *************"); + done(); + }) + + it('testRdbTransDelete0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransDelete0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + const deleteRows = await rdbTrans.delete(updatePredicates); + expect(deleteRows).assertEqual(3); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDelete0001 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDelete0001 failed"); + } + + console.log(TAG + "************* testRdbTransDelete0001 end *************"); + done(); + }) + + it('testRdbTransDelete0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransDelete0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + const deleteRows = await rdbTrans.delete(updatePredicates); + expect(deleteRows).assertEqual(3); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDelete0002 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDelete0002 failed"); + } + + console.log(TAG + "************* testRdbTransDelete0002 end *************"); + done(); + }) + + it('testRdbTransDelete0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransDelete0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + const deleteRows = await rdbTrans.delete(updatePredicates); + expect(deleteRows).assertEqual(3); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDelete0003 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDelete0003 failed"); + } + + console.log(TAG + "************* testRdbTransDelete0003 end *************"); + done(); + }) + + it('testRdbTransDelete0011', 0, async (done) => { + console.log(TAG + "************* testRdbTransDelete0011 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + await rdbTrans.delete(updatePredicates); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDelete0011 result count " + resultSet.rowCount); + expect(3).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDelete0011 failed"); + } + + console.log(TAG + "************* testRdbTransDelete0011 end *************"); + done(); + }) + + it('testRdbTransDelete0012', 0, async (done) => { + console.log(TAG + "************* testRdbTransDelete0012 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + await rdbTrans.delete(updatePredicates); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDelete0012 result count " + resultSet.rowCount); + expect(3).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDelete0012 failed"); + } + + console.log(TAG + "************* testRdbTransDelete0012 end *************"); + done(); + }) + + it('testRdbTransDelete0013', 0, async (done) => { + console.log(TAG + "************* testRdbTransDelete0013 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + await rdbTrans.delete(updatePredicates); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDelete0013 result count " + resultSet.rowCount); + expect(3).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDelete0013 failed"); + } + + console.log(TAG + "************* testRdbTransDelete0013 end *************"); + done(); + }) + + it('testRdbTransDeleteSync0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransDeleteSync0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + const deleteRows = rdbTrans.deleteSync(updatePredicates); + expect(deleteRows).assertEqual(3); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDeleteSync0001 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDeleteSync0001 failed"); + } + + console.log(TAG + "************* testRdbTransDeleteSync0001 end *************"); + done(); + }) + + it('testRdbTransDeleteSync0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransDeleteSync0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + const deleteRows = rdbTrans.deleteSync(updatePredicates); + expect(deleteRows).assertEqual(3); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDeleteSync0002 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDeleteSync0002 failed"); + } + + console.log(TAG + "************* testRdbTransDeleteSync0002 end *************"); + done(); + }) + + it('testRdbTransDeleteSync0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransDeleteSync0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + const deleteRows = rdbTrans.deleteSync(updatePredicates); + expect(deleteRows).assertEqual(3); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDeleteSync0003 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.goToFirstRow(); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDeleteSync0003 failed"); + } + + console.log(TAG + "************* testRdbTransDeleteSync0003 end *************"); + done(); + }) + + it('testRdbTransDeleteSync0011', 0, async (done) => { + console.log(TAG + "************* testRdbTransDeleteSync0011 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + const deleteRows = rdbTrans.deleteSync(updatePredicates); + expect(deleteRows).assertEqual(3); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDeleteSync0011 result count " + resultSet.rowCount); + expect(3).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDeleteSync0011 failed"); + } + + console.log(TAG + "************* testRdbTransDeleteSync0011 end *************"); + done(); + }) + + it('testRdbTransDeleteSync0012', 0, async (done) => { + console.log(TAG + "************* testRdbTransDeleteSync0012 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + const deleteRows = rdbTrans.deleteSync(updatePredicates); + expect(deleteRows).assertEqual(3); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDeleteSync0012 result count " + resultSet.rowCount); + expect(3).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDeleteSync0012 failed"); + } + + console.log(TAG + "************* testRdbTransDeleteSync0012 end *************"); + done(); + }) + + it('testRdbTransDeleteSync0013', 0, async (done) => { + console.log(TAG + "************* testRdbTransDeleteSync0013 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(3).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rowId = await rdbStore.batchInsert("test", valueBuckets); + expect(rowId).assertEqual(3); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const updatePredicates = new data_relationalStore.RdbPredicates("test"); + updatePredicates.equalTo('name', 'lisi'); + const deleteRows = rdbTrans.deleteSync(updatePredicates); + expect(deleteRows).assertEqual(3); + await rdbTrans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransDeleteSync0013 result count " + resultSet.rowCount); + expect(3).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransDeleteSync0013 failed"); + } + + console.log(TAG + "************* testRdbTransDeleteSync0013 end *************"); + done(); + }) + + it('testRdbTransQuery0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransQuery0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbTrans.query(predicates); + console.log(TAG + "testRdbTransQuery0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + await rdbTrans.commit(); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransQuery0001 failed"); + } + + console.log(TAG + "************* testRdbTransQuery0001 end *************"); + done(); + }) + + it('testRdbTransQuery0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransQuery0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbTrans.query(predicates); + console.log(TAG + "testRdbTransQuery0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + await rdbTrans.commit(); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransQuery0002 failed"); + } + + console.log(TAG + "************* testRdbTransQuery0002 end *************"); + done(); + }) + + it('testRdbTransQuery0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransQuery0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbTrans.query(predicates); + console.log(TAG + "testRdbTransQuery0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + await rdbTrans.commit(); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransQuery0003 failed"); + } + + console.log(TAG + "************* testRdbTransQuery0003 end *************"); + done(); + }) + + it('testRdbTransQuery0011', 0, async (done) => { + console.log(TAG + "************* testRdbTransQuery0011 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbTrans.querySync(predicates); + console.log(TAG + "testRdbTransQuery0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + await rdbTrans.commit(); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransQuery0011 failed"); + } + + console.log(TAG + "************* testRdbTransQuery0011 end *************"); + done(); + }) + + it('testRdbTransQuery0012', 0, async (done) => { + console.log(TAG + "************* testRdbTransQuery0012 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbTrans.querySync(predicates); + console.log(TAG + "testRdbTransQuery0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + await rdbTrans.commit(); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransQuery0012 failed"); + } + + console.log(TAG + "************* testRdbTransQuery0012 end *************"); + done(); + }) + + it('testRdbTransQuery0013', 0, async (done) => { + console.log(TAG + "************* testRdbTransQuery0013 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbTrans.querySync(predicates); + console.log(TAG + "testRdbTransQuery0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + await rdbTrans.commit(); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransQuery0013 failed"); + } + + console.log(TAG + "************* testRdbTransQuery0013 end *************"); + done(); + }) + + it('testRdbTransSameThreadInsert0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadInsert0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await insertInThread(context, data_relationalStore.TransactionType.DEFERRED, 10); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadInsert0001 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadInsert0001 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadInsert0001 end *************"); + done(); + }) + + it('testRdbTransSameThreadInsert0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadInsert0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await insertInThread(context, data_relationalStore.TransactionType.DEFERRED, 10); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadInsert0002 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadInsert0002 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadInsert0002 end *************"); + done(); + }) + + it('testRdbTransSameThreadInsert0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadInsert0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await insertInThread(context, data_relationalStore.TransactionType.DEFERRED, 10); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadInsert0003 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadInsert0003 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadInsert0003 end *************"); + done(); + }) + + it('testRdbTransSameThreadInsert0004', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadInsert0004 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + console.log(TAG + "before second trans create"); + const errCode = await insertInThread(context, data_relationalStore.TransactionType.DEFERRED, 10); + console.log(TAG + "after second trans create"); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + console.log(TAG + "before query predicates create"); + let predicates = new data_relationalStore.RdbPredicates("test"); + console.log(TAG + "after query predicates create"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadInsert0004 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadInsert0004 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadInsert0004 end *************"); + done(); + }) + + it('testRdbTransSameThreadInsert0005', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadInsert0005 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await insertInThread(context, data_relationalStore.TransactionType.DEFERRED, 10); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadInsert0005 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadInsert0005 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadInsert0005 end *************"); + done(); + }) + + it('testRdbTransSameThreadInsert0006', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadInsert0006 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await insertInThread(context, data_relationalStore.TransactionType.DEFERRED, 10); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadInsert0006 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadInsert0006 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadInsert0006 end *************"); + done(); + }) + + it('testRdbTransSameThreadInsert0007', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadInsert0007 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await insertInThread(context, data_relationalStore.TransactionType.DEFERRED, 10); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadInsert0007 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadInsert0007 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadInsert0007 end *************"); + done(); + }) + + it('testRdbTransSameThreadInsert0008', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadInsert0008 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await insertInThread(context, data_relationalStore.TransactionType.EXCLUSIVE, 10); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadInsert0008 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadInsert0008 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadInsert0008 end *************"); + done(); + }) + + it('testRdbTransSameThreadInsert0009', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadInsert0009 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await insertInThread(context, data_relationalStore.TransactionType.EXCLUSIVE, 10); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadInsert0009 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadInsert0009 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadInsert0009 end *************"); + done(); + }) + + it('testRdbTransSameThreadQuery0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadQuery0001 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const rowCount = await queryInThread(context, data_relationalStore.TransactionType.DEFERRED, 'select * from test'); + expect(rowCount).assertEqual(0); + + await rdbTrans.commit(); + + { + const rowCount = await queryInThread(context, data_relationalStore.TransactionType.DEFERRED, 'select * from test'); + expect(rowCount).assertEqual(10); + } + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadQuery0001 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadQuery0001 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadQuery0001 end *************"); + done(); + }) + + it('testRdbTransSameThreadQuery0002', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadQuery0002 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const rowCount = await queryInThread(context, data_relationalStore.TransactionType.DEFERRED, 'select * from test'); + expect(rowCount).assertEqual(0); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadQuery0002 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadQuery0002 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadQuery0002 end *************"); + done(); + }) + + it('testRdbTransSameThreadQuery0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadQuery0003 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + + await rdbStore.batchInsert('test', valueBuckets); + + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const rowCount = await queryInThread(context, data_relationalStore.TransactionType.DEFERRED, 'select * from test'); + expect(rowCount).assertEqual(10); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadQuery0003 result count " + resultSet.rowCount); + expect(20).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadQuery0003 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadQuery0003 end *************"); + done(); + }) + + it('testRdbTransSameThreadQuery0004', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadQuery0004 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await queryInThread(context, data_relationalStore.TransactionType.IMMEDIATE, 'select * from test'); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadQuery0004 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadQuery0004 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadQuery0004 end *************"); + done(); + }) + + it('testRdbTransSameThreadQuery0005', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadQuery0005 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await queryInThread(context, data_relationalStore.TransactionType.IMMEDIATE, 'select * from test'); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadQuery0005 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadQuery0005 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadQuery0005 end *************"); + done(); + }) + + it('testRdbTransSameThreadQuery0006', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadQuery0006 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await queryInThread(context, data_relationalStore.TransactionType.IMMEDIATE, 'select * from test'); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadQuery0006 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadQuery0006 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadQuery0006 end *************"); + done(); + }) + + it('testRdbTransSameThreadQuery0007', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadQuery0007 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await queryInThread(context, data_relationalStore.TransactionType.EXCLUSIVE, 'select * from test'); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadQuery0007 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadQuery0007 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadQuery0007 end *************"); + done(); + }) + + it('testRdbTransSameThreadQuery0008', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadQuery0008 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await queryInThread(context, data_relationalStore.TransactionType.EXCLUSIVE, 'select * from test'); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadQuery0008 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadQuery0008 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadQuery0008 end *************"); + done(); + }) + + it('testRdbTransSameThreadQuery0009', 0, async (done) => { + console.log(TAG + "************* testRdbTransSameThreadQuery0009 start *************"); + try { + const u8 = new Uint8Array([1, 2, 3]); + const valueBuckets = new Array(10).fill(0).map(() => { + return { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + }) + const rdbTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + + const insertCount = await rdbTrans.batchInsert('test', valueBuckets); + expect(insertCount).assertEqual(10); + + const errCode = await queryInThread(context, data_relationalStore.TransactionType.EXCLUSIVE, 'select * from test'); + expect(errCode).assertEqual(14800024); + + await rdbTrans.commit(); + + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = rdbStore.querySync(predicates); + console.log(TAG + "testRdbTransSameThreadQuery0009 result count " + resultSet.rowCount); + expect(10).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransSameThreadQuery0009 failed"); + } + + console.log(TAG + "************* testRdbTransSameThreadQuery0009 end *************"); + done(); + }) + + /** + * @tc.name rdb transaction insert test + * @tc.number testRdbTransactionInsert0001 + * @tc.desc rdb transaction insert & commit, the result comes out is 3 items; + */ + it('testRdbTransactionInsert0001', 0, async (done) => { + console.log(TAG + "************* testRdbStoreInsert0001 start *************"); + const u8 = new Uint8Array([1, 2, 3]); + try { + const rdbTrans = await rdbStore.createTransaction(); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await rdbTrans.insert("test", valueBucket); + await rdbTrans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransactionInsert0001 result count " + resultSet.rowCount); + expect(1).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + console.log(TAG + e); + expect(null).assertFail(); + console.log(TAG + "testRdbTransactionInsert0001 failed"); + } + done(); + console.log(TAG + "************* testRdbTransactionInsert0001 end *************"); + }) + + /** + * @tc.name rdb transaction insert test + * @tc.number testRdbTransactionInsert0001 + * @tc.desc rdb transaction insert & commit, the result comes out is 3 items; + */ + it('testRdbTransactionInsert0002', 0, async (done) => { + console.log(TAG + "************* testRdbStoreInsert0002 start *************"); + const u8 = new Uint8Array([1, 2, 3]); + try { + const trans = await rdbStore.createTransaction(); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await trans.insert("test", valueBucket); + const valueBucket1 = { + "name": "zhangsan", + "age": 20, + "salary": 9.5, + "blobType": u8, + }; + await trans.insert("test", valueBucket1); + const valueBucket2 = { + "name": "wangwu", + "age": 16, + "salary": 99, + "blobType": u8, + }; + await trans.insert("test", valueBucket2); + await trans.commit(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(3).assertEqual(resultSet.rowCount); + resultSet.close(); + } catch (e) { + expect(null).assertFail(); + console.log(TAG + "testRdbTransactionInsert0002 failed"); + } + done(); + console.log(TAG + "************* testRdbTransactionInsert0002 end *************"); + }) + + /** + * @tc.name rdb transaction insert test + * @tc.number testRdbTransactionInsert0002 + * @tc.desc while using transaction to insert values, querying the db, + * the result comes out is 0; + */ + it('testRdbTransactionInsert0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransactionInsert0003 start *************"); + const u8 = new Uint8Array([1, 2, 3]); + try { + const trans = await rdbStore.createTransaction(); + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await trans.insert("test", valueBucket); + const valueBucket1 = { + "name": "zhangsan", + "age": 20, + "salary": 9.5, + "blobType": u8, + }; + await trans.insert("test", valueBucket1); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await trans.query(predicates); + expect(2).assertEqual(resultSet.rowCount); + resultSet.close(); + const valueBucket2 = { + "name": "wangwu", + "age": 16, + "salary": 99, + "blobType": u8, + }; + await trans.insert("test", valueBucket2); + await trans.commit(); + } catch (e) { + expect(null).assertFail(); + console.log(TAG + "testRdbTransactionInsert0003 failed"); + } + done(); + console.log(TAG + "************* testRdbTransactionInsert0003 end *************"); + }) + + /** + * @tc.number testRdbTransactionInsert0004 + * @tc.name Abnormal test case of transaction insert, if catch exception then rollback + * @tc.desc 1.Execute beginTransaction + * 2.Insert data (primary key conflict) + * 3.Execute rollBack + * 4.Query data + */ + it('testRdbTransactionRollBack0001', 0, async (done) => { + console.log(TAG + "************* testRdbTransactionRollBack0001 start *************"); + const u8 = new Uint8Array([1, 2, 3]); + const trans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + try { + const valueBucket = { + "id": 1, + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await trans.insert("test", valueBucket); + await trans.insert("test", valueBucket); + trans.commit(); + } catch (e) { + trans.rollback(); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + console.log(TAG + "testRdbTransactionRollBack0001 result count " + resultSet.rowCount); + expect(0).assertEqual(resultSet.rowCount); + resultSet.close(); + } + done(); + console.log(TAG + "************* testRdbTransactionRollBack0001 end *************"); + }) + + /** + * @tc.number testRdbTransactionInsert0005 + * @tc.name Normal test case of transaction, begin transactions within a transaction + * @tc.desc 1.Execute beginTransaction + * 2.Insert data + * 3.Execute beginTransaction + * 4.Insert data + * 5.Execute rollBack + * 6.Insert data + * 7.Execute commit + * 8.Query data + */ + it('testRdbTransactionMulti0003', 0, async (done) => { + console.log(TAG + "************* testRdbTransactionMulti0003 start *************"); + const u8 = new Uint8Array([1, 2, 3]); + let trans = await rdbStore.createTransaction(); + const trans2 = await rdbStore.createTransaction(); + try { + const valueBucket = { + "id": 1, + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + await trans.insert("test", valueBucket); + console.log(TAG + "before second create trans"); + console.log(TAG + "after second create trans"); + const valueBucket1 = { + "name": "zhangsan", + "age": 20, + "salary": 220.5, + "blobType": u8, + }; + await trans2.insert("test", valueBucket1); + } catch (e) { + expect(e.code).assertEqual(14800024) + await trans.rollback(); + await trans2.rollback(); + console.log(TAG + "testRdbTransactionMulti0003 rollback ***** "); + } + done(); + console.log(TAG + "************* testRdbTransactionMulti0003 end *************"); + }) + + console.log(TAG + "*************Unit Test End*************"); +}) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransaction.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransaction.test.js index a468a83e..96c945c3 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransaction.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransaction.test.js @@ -66,7 +66,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionInsert0001', 0, async function (done) { console.log(TAG + "************* testTransactionInsert0001 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { const valueBucket = { "name": "lisi", @@ -93,6 +95,110 @@ describe('rdbStoreTransactionTest', function () { console.log(TAG + "************* testTransactionInsert0001 end *************"); }) + /** + * @tc.number testTransactionInsert0002 + * @tc.name Abnormal test case of transaction, insert a type mismatch data + * @tc.desc 1.Execute beginTransaction + * 2.Insert data + * 3.Execute commit + */ + it('testTransactionInsert0002', 0, async function (done) { + console.log(TAG + "************* testTransactionInsert0002 start *************"); + let u8 = new Uint8Array([1, 2, 3]); + let transaction = await rdbStore?.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + try { + const valueBucket = { + "id": "test", + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + let row = transaction?.insertSync("test", valueBucket); + console.log(TAG + "testTransactionInsert0002 insert row:" + row); + expect(null).assertFail(); + await transaction?.commit(); + } catch (e) { + await transaction?.rollback(); + console.log(TAG + e + " code: " + e.code); + expect(e.code).assertEqual(14800033) + console.log(TAG + "testTransactionInsert0002 failed"); + } + done(); + console.log(TAG + "************* testTransactionInsert0002 end *************"); + }) + + /** + * @tc.number testTransactionInsert0003 + * @tc.name Abnormal test case of transaction, insert with an abnormal table + * @tc.desc 1.Execute beginTransaction + * 2.Insert data to a no exist table + * 3.Execute commit + */ + it('testTransactionInsert0003', 0, async function (done) { + console.log(TAG + "************* testTransactionInsert0003 start *************"); + let u8 = new Uint8Array([1, 2, 3]); + let transaction = await rdbStore?.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + try { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + }; + let row = await transaction?.insert("testNotExist", valueBucket); + console.log(TAG + "testTransactionInsert0003 insert row:" + row); + expect(null).assertFail(); + await transaction?.commit(); + } catch (e) { + await transaction?.rollback(); + console.log(TAG + e + " code: " + e.code); + expect(e.code).assertEqual(14800021) + console.log(TAG + "testTransactionInsert0003 failed"); + } + done(); + console.log(TAG + "************* testTransactionInsert0003 end *************"); + }) + + /** + * @tc.number testTransactionInsert0004 + * @tc.name Abnormal test case of transaction, insert an more attribute data + * @tc.desc 1.Execute beginTransaction + * 2.Insert insert an more attribute data + * 3.Execute commit + */ + it('testTransactionInsert0004', 0, async function (done) { + console.log(TAG + "************* testTransactionInsert0004 start *************"); + let u8 = new Uint8Array([1, 2, 3]); + let transaction = await rdbStore?.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }); + try { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + "notExist": "test" + }; + let row = transaction?.insertSync("test", valueBucket); + console.log(TAG + "testTransactionInsert0004 insert row:" + row); + expect(null).assertFail(); + await transaction?.commit(); + } catch (e) { + await transaction?.rollback(); + console.log(TAG + e + " code: " + e.code); + expect(e.code).assertEqual(14800021) + console.log(TAG + "testTransactionInsert0004 failed"); + } + done(); + console.log(TAG + "************* testTransactionInsert0004 end *************"); + }) + /** * @tc.number testTransactionBatchInsert0001 * @tc.name Normal test case of transactions, insert a row of data @@ -147,7 +253,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionUpdate0001', 0, async function (done) { console.log(TAG + "************* testTransactionUpdate0001 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.IMMEDIATE) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }) try { const valueBucket = { "name": "lisi", @@ -202,7 +310,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionDelete0001', 0, async function (done) { console.log(TAG + "************* testTransactionDelete0001 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }) try { const valueBucket = { "name": "lisi", @@ -240,7 +350,9 @@ describe('rdbStoreTransactionTest', function () { */ it('testExecute0001', 0, async function (done) { console.info(TAG + "************* testExecute0001 start *************"); - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }) try { let ret = await transaction.execute("PRAGMA integrity_check"); expect("ok").assertEqual(ret); @@ -538,7 +650,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionSyncInterface0001', 0, async function (done) { console.log(TAG + "************* testTransactionSyncInterface0001 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { const valueBucket = { "name": "lisi", @@ -591,7 +705,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionRollback0001', 0, async function (done) { console.log(TAG + "************* testTransactionRollback0001 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }) try { const valueBucket = { "name": "lisi", @@ -626,9 +742,13 @@ describe('rdbStoreTransactionTest', function () { */ it('testTransactionIsolation0001', 0, async function (done) { console.log(TAG + "************* testTransactionIsolation0001 start *************"); - var exclusiveTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var exclusiveTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }) try { - var trans = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var trans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }) trans.commit(); expect(null).assertFail() console.log(TAG + "testTransactionIsolation0001 failed"); @@ -655,9 +775,13 @@ describe('rdbStoreTransactionTest', function () { */ it('testTransactionIsolation0002', 0, async function (done) { console.log(TAG + "************* testTransactionIsolation0002 start *************"); - var deferredTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var deferredTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { - var exclusiveTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var exclusiveTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }) try { const valueBucket = { "name": "lisi", @@ -712,7 +836,9 @@ describe('rdbStoreTransactionTest', function () { */ it('testTransactionIsolation0003', 0, async function (done) { console.log(TAG + "************* testTransactionIsolation0003 start *************"); - var immediateTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.IMMEDIATE) + var immediateTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }) try { const valueBucket = { "name": "lisi", @@ -763,7 +889,9 @@ describe('rdbStoreTransactionTest', function () { */ it('testTransactionIsolation0004', 0, async function (done) { console.log(TAG + "************* testTransactionIsolation0004 start *************"); - var deferredTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var deferredTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { const valueBucket = { "name": "lisi", @@ -823,8 +951,12 @@ describe('rdbStoreTransactionTest', function () { */ it('testTransactionIsolation0005', 0, async function (done) { console.log(TAG + "************* testTransactionIsolation0005 start *************"); - var deferredTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) - var immediateTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.IMMEDIATE) + var deferredTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) + var immediateTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }) try { const valueBucket = { "name": "lisi", @@ -882,8 +1014,12 @@ describe('rdbStoreTransactionTest', function () { */ it('testTransactionIsolation0006', 0, async function (done) { console.log(TAG + "************* testTransactionIsolation0006 start *************"); - var deferredTrans1 = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) - var deferredTrans2 = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var deferredTrans1 = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) + var deferredTrans2 = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { const valueBucket = { "name": "lisi", @@ -961,9 +1097,13 @@ describe('rdbStoreTransactionTest', function () { */ it('testTransactionIsolation0007', 0, async function (done) { console.log(TAG + "************* testTransactionIsolation0007 start *************"); - var deferredTrans1 = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var deferredTrans1 = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { - var exclusiveTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var exclusiveTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }) try { const valueBucket = { "name": "lisi", @@ -979,7 +1119,9 @@ describe('rdbStoreTransactionTest', function () { console.log(TAG + "testTransactionIsolation0007 deferredTrans1 querySqlSync after exclusiveTrans commit count " + resultSet.rowCount); expect(1).assertEqual(resultSet.rowCount); - var deferredTrans2 = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var deferredTrans2 = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { resultSet = deferredTrans2.querySqlSync("select * from test where name = ?", ["lisi"]); console.log(TAG + "testTransactionIsolation0007 deferredTrans2 querySqlSync after exclusiveTrans commit count " + resultSet.rowCount); @@ -1023,7 +1165,9 @@ describe('rdbStoreTransactionTest', function () { */ it('testTransactionIsolation0008', 0, async function (done) { console.log(TAG + "************* testTransactionIsolation0008 start *************"); - var deferredTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var deferredTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { const valueBucket = { "name": "lisi", @@ -1037,7 +1181,9 @@ describe('rdbStoreTransactionTest', function () { expect(1).assertEqual(resultSet.rowCount); resultSet.close() try { - var exclusiveTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var exclusiveTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }) console.log(TAG + "begin EXCLUSIVE success abnormal"); exclusiveTrans.rollback(); } catch (e) { @@ -1052,7 +1198,9 @@ describe('rdbStoreTransactionTest', function () { await deferredTrans.commit(); try { - var exclusiveTrans = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var exclusiveTrans = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }) console.log(TAG + "begin EXCLUSIVE success"); try { resultSet = exclusiveTrans.querySqlSync("select * from test"); @@ -1097,8 +1245,12 @@ describe('rdbStoreTransactionTest', function () { */ it('testTransactionIsolation0009', 0, async function (done) { console.log(TAG + "************* testTransactionIsolation0009 start *************"); - var deferredTrans1 = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) - var deferredTrans2 = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var deferredTrans1 = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) + var deferredTrans2 = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { const valueBucket = { "name": "lisi", @@ -1187,7 +1339,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionEnd0001', 0, async function (done) { console.log(TAG + "************* testTransactionEnd0001 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.IMMEDIATE) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }) try { const valueBucket = { "name": "lisi", @@ -1229,7 +1383,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionEnd0002', 0, async function (done) { console.log(TAG + "************* testTransactionEnd0002 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }) let resultSet; try { const valueBucket = { @@ -1266,7 +1422,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionEnd0003', 0, async function (done) { console.log(TAG + "************* testTransactionEnd0003 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) const valueBucket = { "name": "lisi", "age": 18, @@ -1305,7 +1463,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionEnd0004', 0, async function (done) { console.log(TAG + "************* testTransactionEnd0004 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.IMMEDIATE) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }) try { const valueBucket = { "name": "lisi", @@ -1352,7 +1512,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionEnd0005', 0, async function (done) { console.log(TAG + "************* testTransactionEnd0005 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.EXCLUSIVE) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.EXCLUSIVE + }) try { const valueBucket = { "name": "lisi", @@ -1393,7 +1555,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionEnd0006', 0, async function (done) { console.log(TAG + "************* testTransactionEnd0006 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { const valueBucket = { "name": "lisi", @@ -1432,7 +1596,9 @@ describe('rdbStoreTransactionTest', function () { it('testTransactionEnd0007', 0, async function (done) { console.log(TAG + "************* testTransactionEnd0007 start *************"); var u8 = new Uint8Array([1, 2, 3]) - var transaction = await rdbStore.createTransaction(data_relationalStore.TransactionType.DEFERRED) + var transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }) try { const valueBucket = { "name": "lisi", @@ -1460,5 +1626,75 @@ describe('rdbStoreTransactionTest', function () { console.log(TAG + "************* testTransactionEnd0007 end *************"); }) + /** + * @tc.number testTransactionBusy0001 + * @tc.name Abnormal test case of createTransaction + * @tc.desc 1.Execute beginTransaction 5 times + */ + it('testTransactionBusy0001', 0, async function (done) { + console.log(TAG + "************* testTransactionBusy0001 start *************"); + let transactions = []; + try { + for (let i = 0; i < 5; i++) { + transactions.push(await rdbStore?.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + })); + console.log(TAG + "testTransactionBusy0001 createTransaction success. i " + i); + } + } catch (e) { + console.log(TAG + e + " code: " + e.code); + // expect(e.code).assertEqual(14800000) + expect(e.code).assertEqual(14800015) + console.log(TAG + "testTransactionBusy0001 failed"); + } + done(); + transactions.forEach(element => { + element?.rollback(); + console.log(TAG + "testTransactionBusy0001 rollback"); + }); + console.log(TAG + "************* testTransactionBusy0001 end *************"); + }) + + /** + * @tc.number testTransactionWithReadOnlyStore0001 + * @tc.name createTransactionWithReadOnlyStore + * @tc.desc 1.Get a readOnly store + * 2.createTransaction with readOnly store + */ + it('testTransactionWithReadOnlyStore0001', 0, async function (done) { + console.log(TAG + "************* testTransactionWithReadOnlyStore0001 start *************"); + let storeConfig = { + name: "ReadOnlyTransactionTest.db", + securityLevel: data_relationalStore.SecurityLevel.S1, + } + let store = await data_relationalStore.getRdbStore(context, storeConfig); + await store.close() + storeConfig.isReadOnly = true; + let readOnlyStore = await data_relationalStore.getRdbStore(context, storeConfig); + expect(readOnlyStore === null).assertFalse(); + try { + let transaction = await readOnlyStore?.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + console.log(TAG + "testTransactionWithReadOnlyStore0001 createTransaction success"); + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + }; + let row = transaction?.insertSync("test", valueBucket); + console.log(TAG + "testTransactionWithReadOnlyStore0001 insert row:" + row); + await transaction?.rollback(); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(e.code).assertEqual(801) + console.log(TAG + "testTransactionWithReadOnlyStore0001 success"); + } + await data_relationalStore.deleteRdbStore(context, storeConfig); + done(); + console.log(TAG + "************* testTransactionWithReadOnlyStore0001 end *************"); + }) + console.log(TAG + "*************Unit Test End*************"); }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbstoreEncryptionJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbstoreEncryptionJsunit.test.js index 046888aa..ffff620c 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbstoreEncryptionJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbstoreEncryptionJsunit.test.js @@ -616,7 +616,7 @@ describe('rdbEncryptTest', function () { /** * @tc.name RDB decrypt test * @tc.number SUB_DDM_RDB_JS_RdbDecryptTest_0080 - * @tc.desc RDB decrypt function invalid page size (512) test + * @tc.desc RDB decrypt function invalid page size (-1/512/4294967296/MAX_SAFE_INTEGER) */ it('RdbDecryptTest_0080', 0, async function () { console.info(TAG + "************* RdbDecryptTest_0080 start *************") @@ -636,7 +636,34 @@ describe('rdbEncryptTest', function () { try { let rdbStore = await data_relationalStore.getRdbStore(context, invalid_page_size_config) expect().assertFail() - console.error(`Invalid page size 512 should fail, error code: ${err.code}, err message: ${err.message}`); + console.error(`Page size 512 should fail, error code: ${err.code}, err message: ${err.message}`); + } catch (err) { + expect("401").assertEqual(err.code) + } + + invalid_page_size_config.cryptoParam.cryptoPageSize = -1 + try { + let rdbStore = await data_relationalStore.getRdbStore(context, invalid_page_size_config) + expect().assertFail() + console.error(`Page size -1 should fail, error code: ${err.code}, err message: ${err.message}`); + } catch (err) { + expect("401").assertEqual(err.code) + } + + invalid_page_size_config.cryptoParam.cryptoPageSize = 4294967296 + try { + let rdbStore = await data_relationalStore.getRdbStore(context, invalid_page_size_config) + expect().assertFail() + console.error(`Page size 4294967296 should fail, error code: ${err.code}, err message: ${err.message}`); + } catch (err) { + expect("401").assertEqual(err.code) + } + + invalid_page_size_config.cryptoParam.cryptoPageSize = Number.MAX_SAFE_INTEGER + try { + let rdbStore = await data_relationalStore.getRdbStore(context, invalid_page_size_config) + expect().assertFail() + console.error(`Page size MAX_SAFE_INTEGER should fail, error code: ${err.code}, err msg: ${err.message}`); } catch (err) { expect("401").assertEqual(err.code) } @@ -644,5 +671,43 @@ describe('rdbEncryptTest', function () { console.log(TAG + "************* RdbDecryptTest_0080 end *************") }) + /** + * @tc.name RDB decrypt test + * @tc.number SUB_DDM_RDB_JS_RdbDecryptTest_0090 + * @tc.desc RDB decrypt function valid page size (1024/65536) test + */ + it('RdbDecryptTest_0090', 0, async function () { + console.info(TAG + "************* RdbDecryptTest_0090 start *************") + let valid_page_size_config = { + name: "validPageSize.db", + securityLevel: data_relationalStore.SecurityLevel.S1, + encrypt: true, + cryptoParam: { + encryptionKey: new Uint8Array(['t', 'e', 's', 't', 'k', 'e', 'y']), + iterationCount: 25000, + encryptionAlgo: data_relationalStore.EncryptionAlgo.AES_256_CBC, + hmacAlgo: data_relationalStore.HmacAlgo.SHA512, + kdfAlgo: data_relationalStore.KdfAlgo.KDF_SHA512, + cryptoPageSize: 1024 + } + } + try { + let rdbStore = await data_relationalStore.getRdbStore(context, valid_page_size_config) + } catch (err) { + console.error(`Valid page size 1024 failed, error code: ${err.code}, err message: ${err.message}`); + expect().assertFail() + } + + valid_page_size_config.cryptoParam.cryptoPageSize = 65536 + try { + let rdbStore = await data_relationalStore.getRdbStore(context, valid_page_size_config) + } catch (err) { + console.error(`Valid page size 65536 failed, error code: ${err.code}, err message: ${err.message}`); + expect().assertFail() + } + + console.log(TAG + "************* RdbDecryptTest_0090 end *************") + }) + console.log(TAG + "*************Unit Test End*************") }) diff --git a/relational_store/test/native/rdb/BUILD.gn b/relational_store/test/native/rdb/BUILD.gn index f4dc041c..aa0e8e37 100644 --- a/relational_store/test/native/rdb/BUILD.gn +++ b/relational_store/test/native/rdb/BUILD.gn @@ -86,6 +86,7 @@ ohos_unittest("NativeRdbTest") { "unittest/rdb_distributed_test.cpp", "unittest/rdb_double_write_test.cpp", "unittest/rdb_encrypt_decrypt_test.cpp", + "unittest/rdb_execute_rd_test.cpp", "unittest/rdb_execute_test.cpp", "unittest/rdb_get_store_test.cpp", "unittest/rdb_helper_test.cpp", diff --git a/relational_store/test/native/rdb/unittest/rdb_execute_rd_test.cpp b/relational_store/test/native/rdb/unittest/rdb_execute_rd_test.cpp new file mode 100644 index 00000000..5d10b0f9 --- /dev/null +++ b/relational_store/test/native/rdb/unittest/rdb_execute_rd_test.cpp @@ -0,0 +1,921 @@ +/* + +Copyright (c) 2024 Huawei Device Co., Ltd. +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 + +#include + +#include "common.h" +#include "grd_api_manager.h" +#include "rd_utils.h" +#include "rdb_errno.h" +#include "rdb_helper.h" +#include "rdb_open_callback.h" + +using namespace testing::ext; +using namespace OHOS::NativeRdb; + +class RdbExecuteRdTest : public testing::TestWithParam { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static const std::string databaseName; + static std::shared_ptr store; +}; + +INSTANTIATE_TEST_CASE_P(, RdbExecuteRdTest, testing::Values(false, true)); + +const std::string RdbExecuteRdTest::databaseName = RDB_TEST_PATH + "execute_test.db"; +std::shared_ptr RdbExecuteRdTest::store = nullptr; + +class ExecuteTestOpenRdCallback : public RdbOpenCallback { +public: + int OnCreate(RdbStore &store) override; + int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override; +}; + +int ExecuteTestOpenRdCallback::OnCreate(RdbStore &store) +{ + return E_OK; +} + +int ExecuteTestOpenRdCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion) +{ + return E_OK; +} + +void RdbExecuteRdTest::SetUpTestCase(void) +{ +} + +void RdbExecuteRdTest::TearDownTestCase(void) +{ +} + +void RdbExecuteRdTest::SetUp(void) +{ + if (!IsUsingArkData()) { + GTEST_SKIP() << "Current testcase is not compatible from current rdb"; + } + int errCode = E_OK; + RdbHelper::DeleteRdbStore(RdbExecuteRdTest::databaseName); + RdbStoreConfig config(RdbExecuteRdTest::databaseName); + config.SetIsVector(true); + config.SetEncryptStatus(GetParam()); + ExecuteTestOpenRdCallback helper; + RdbExecuteRdTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_NE(RdbExecuteRdTest::store, nullptr); + EXPECT_EQ(errCode, E_OK); +} + +void RdbExecuteRdTest::TearDown(void) +{ + RdbExecuteRdTest::store = nullptr; + RdbHelper::DeleteRdbStore(RdbExecuteRdTest::databaseName); +} + +/** +@tc.name: RdbStore_Execute_001 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_001, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + + int64_t id = 0; + ValuesBucket values; + values.PutInt("id", 1); + values.PutString("name", std::string("zhangsan")); + values.PutInt("age", 18); + values.PutDouble("salary", 100.5); + values.PutBlob("blobType", std::vector{ 1, 2, 3 }); + + values.Clear(); + values.PutInt("id", 2); + values.PutString("name", std::string("lisi")); + values.PutInt("age", 19); + values.PutDouble("salary", 200.5); + values.PutBlob("blobType", std::vector{ 4, 5, 6 }); + + values.Clear(); + values.PutInt("id", 3); + values.PutString("name", std::string("wangyjing")); + values.PutInt("age", 20); + values.PutDouble("salary", 300.5); + values.PutBlob("blobType", std::vector{ 7, 8, 9 }); + std::vector bindArgs = + std::vector{ ValueObject(std::string("18")), ValueObject(std ::string("20")) }; + + std::string sqlDelNoBind = "DELETE FROM test WHERE age = 19"; + std::string sqlSelect = "SELECT * FROM test WHERE age = ? OR age = ?"; + std::string sqlDelete = "DELETE FROM test WHERE age = ? OR age = ?"; + EXPECT_EQ(store->ExecuteSql(sqlDelete.c_str(), bindArgs), E_NOT_SUPPORT); + EXPECT_EQ(store->ExecuteSql(sqlDelNoBind.c_str()), E_NOT_SUPPORT); + + int64_t count = 0; + EXPECT_EQ(store->ExecuteAndGetLong(count, "SELECT COUNT() FROM test where age = 19"), E_NOT_SUPPORT); + EXPECT_EQ(store->ExecuteAndGetLong(count, "SELECT COUNT() FROM test"), E_NOT_SUPPORT); + EXPECT_EQ(store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test"), E_NOT_SUPPORT); + EXPECT_EQ(store->Insert(id, "test", values), E_NOT_SUPPORT); +} + +/** +@tc.name: RdbStore_Execute_002 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_002, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + std::pair res1 = {}; + std::pair res2 = {}; + res1 = store->BeginTrans(); + EXPECT_EQ(res1.first, E_OK); + EXPECT_NE(res1.second, 0); + res2 = store->BeginTrans(); + EXPECT_EQ(res2.first, E_OK); + EXPECT_NE(res2.second, 0); + EXPECT_EQ(store->RollBack(res1.second), E_OK); + EXPECT_EQ(store->Commit(res2.second), E_OK); +} + +/** +@tc.name: RdbStore_Execute_003 +@tc.desc: test RdbStore Execute in vector mode. Repeatly require trx. +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_003, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + std::vector> results = {}; + for (uint32_t i = 0; i < 100; i++) { // Get 100 trxs + std::pair res = {}; + res = store->BeginTrans(); + EXPECT_TRUE((res.first == E_OK) || (res.first == E_DATABASE_BUSY)); + results.push_back(res); + } + for (uint32_t i = 0; i < 100; i++) { // Commit 100 trxs + if (results[i].first == E_OK) { + EXPECT_EQ(store->RollBack(results[i].second), E_OK); + } + } +} + +/** +@tc.name: RdbStore_Execute_004 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_004, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + std::string sqlCreateTable = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, repr floatvector(8));"; + std::string sqlInsert = "INSERT INTO test VALUES(1, '[1.2, 0.3, 3.2, 1.6, 2.5, 3.1, 0.8, 0.4]');"; + std::string sqlQuery = "SELECT id FROM test order by repr <-> '[1.1, 0.3, 2.2, 6.6, 1.5, 3.1, 0.6, 0.2]' limit 3;"; + + std::pair res = {}; + res = store->Execute(sqlCreateTable.c_str(), {}, 0); + EXPECT_EQ(res.first, E_OK); + + std::pair res1 = {}; + res1 = store->BeginTrans(); + EXPECT_EQ(res1.first, E_OK); + EXPECT_NE(res1.second, 0); + + res = store->Execute(sqlInsert.c_str(), {}, res1.second); + EXPECT_EQ(res.first, E_OK); + EXPECT_EQ(store->Commit(res1.second), E_OK); + res = store->Execute("DROP TABLE test;", {}, 0); + EXPECT_EQ(res.first, E_OK); +} + +/** +@tc.name: RdbStore_Execute_005 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_005, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + std::string sqlCreateTable = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, repr floatvector(8));"; + std::string sqlInsert = "INSERT INTO test VALUES(1, '[1.2, 0.3, 3.2, 1.6, 2.5, 3.1, 0.8, 0.4]');"; + std::string sqlQuery = "SELECT id FROM test order by repr <-> '[1.1, 0.3, 2.2, 6.6, 1.5, 3.1, 0.6, 0.2]' limit 3;"; + + std::pair res = {}; + res = store->Execute(sqlCreateTable.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + res = store->Execute(sqlInsert.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + std::shared_ptr resultSet = store->QueryByStep(sqlQuery.c_str(), std::vector()); + EXPECT_NE(resultSet, nullptr); + EXPECT_EQ(resultSet->GoToNextRow(), E_OK); + std::vector colNames = {}; + resultSet->GetAllColumnNames(colNames); + EXPECT_EQ(colNames.size(), 1); + int columnIndex = 0; + int intVal = 0; + resultSet->GetColumnIndex("id", columnIndex); + resultSet->GetInt(columnIndex, intVal); + EXPECT_EQ(columnIndex, 0); + EXPECT_EQ(intVal, 1); + EXPECT_EQ(E_OK, resultSet->Close()); + res = store->Execute("DROP TABLE test;"); + EXPECT_EQ(E_OK, res.first); +} + +/** +@tc.name: RdbStore_Execute_006 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_006, TestSize.Level1) +{ + std::string sqlCreateTable = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, repr floatvector(8));"; + std::string sqlInsert = "INSERT INTO test VALUES(1, '[1.2, 0.3, 3.2, 1.6, 2.5, 3.1, 0.8, 0.4]');"; + std::string sqlBeginTrans = "begin;"; + + std::string dbPath = "/data/test/execute_test1.db"; + std::string configStr = + "{\"pageSize\":8, \"crcCheckEnable\":0, \"redoFlushByTrx\":1, \"bufferPoolSize\":10240," + "\"sharedModeEnable\":1, \"metaInfoBak\":1, \"maxConnNum\":500 }"; + + GRD_DB *db2 = nullptr; + GRD_DB *db4 = nullptr; + EXPECT_EQ(RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), GRD_DB_OPEN_CREATE, &db2), E_OK); + EXPECT_EQ(RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), GRD_DB_OPEN_CREATE, &db4), E_OK); + + GRD_SqlStmt *stmt = nullptr; + EXPECT_EQ(RdUtils::RdSqlPrepare(db2, sqlCreateTable.c_str(), sqlCreateTable.size(), &stmt, nullptr), E_OK); + EXPECT_EQ(RdUtils::RdSqlStep(stmt), E_OK); + EXPECT_EQ(RdUtils::RdSqlFinalize(stmt), E_OK); + + stmt = nullptr; + EXPECT_EQ(RdUtils::RdSqlPrepare(db4, sqlBeginTrans.c_str(), sqlBeginTrans.size(), &stmt, nullptr), E_OK); + EXPECT_EQ(RdUtils::RdSqlStep(stmt), E_OK); + EXPECT_EQ(RdUtils::RdSqlFinalize(stmt), E_OK); + + stmt = nullptr; + EXPECT_EQ(RdUtils::RdSqlPrepare(db4, sqlInsert.c_str(), sqlInsert.size(), &stmt, nullptr), E_OK); + EXPECT_EQ(RdUtils::RdSqlStep(stmt), E_OK); + EXPECT_EQ(RdUtils::RdSqlFinalize(stmt), E_OK); + EXPECT_EQ(RdUtils::RdDbClose(db2, 0), E_OK); + EXPECT_EQ(RdUtils::RdDbClose(db4, 0), E_OK); +} + +std::string GetRandVector(uint32_t maxElementNum, uint16_t dim) +{ + if (maxElementNum == 0) { + return ""; + } + unsigned int randomNumberSeed = time(nullptr); + std::string res = "["; + for (uint16_t i = 0; i < dim; i++) { + uint32_t intPart = (rand_r(&randomNumberSeed) % maxElementNum); + intPart += 1; + uint32_t tenths = (rand_r(&randomNumberSeed) % 10); // 10是用来限制小数点后的数字不能超过10 + res += std::to_string(intPart); + res += "."; + res += std::to_string(tenths); + res += ", "; + } + res.pop_back(); + res.pop_back(); + res += "]"; + return res; +} + +constexpr uint32_t MAX_INT_PART = 10; +constexpr uint16_t LARGE_ANN_INDEX_DIM = 8; +std::shared_ptr CreateIdxAndSelect(std::string &sqlSelect) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + + std::string sqlCreateTable = + "CREATE TABLE test(id int primary key, repr floatvector(" + std::to_string(LARGE_ANN_INDEX_DIM) + "));"; + std::string sqlCreateIndex = "CREATE INDEX diskann_l2_idx ON test USING GSIVFFLAT(repr L2);"; + + std::pair res = {}; + res = store->Execute(sqlCreateTable.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + res = store->Execute(sqlCreateIndex.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + for (uint16_t i = 0; i < 10; i++) { // iterate 10 times to insert 10 data + std::string sqlInsert = "INSERT INTO test VALUES(1000000" + std::to_string(i) + ", '" + + GetRandVector(MAX_INT_PART, LARGE_ANN_INDEX_DIM) + "');"; + res = store->Execute(sqlInsert.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + } + std::shared_ptr resultSet = store->QueryByStep(sqlSelect.c_str(), std::vector()); + EXPECT_NE(resultSet, nullptr); + + bool isStarted = false; + bool isAtFirstRow = false; + EXPECT_EQ(E_OK, resultSet->IsStarted(isStarted)); + EXPECT_EQ(E_OK, resultSet->IsAtFirstRow(isAtFirstRow)); + EXPECT_EQ(false, isStarted); + EXPECT_EQ(false, isAtFirstRow); + + EXPECT_EQ(E_OK, resultSet->GoToNextRow()); + EXPECT_EQ(E_OK, resultSet->IsStarted(isStarted)); + EXPECT_EQ(E_OK, resultSet->IsAtFirstRow(isAtFirstRow)); + EXPECT_EQ(true, isStarted); + EXPECT_EQ(true, isAtFirstRow); + + std::vector colNames = {}; + resultSet->GetAllColumnNames(colNames); + EXPECT_EQ(colNames.size(), 2); // Expect 2 columns + return resultSet; +} + +/** +@tc.name: RdbStore_Execute_007 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +constexpr uint16_t SELECT_RES_NUM = 3; +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_007, TestSize.Level1) +{ + std::string sqlSelect = "SELECT * FROM test ORDER BY repr <-> '" + + GetRandVector(MAX_INT_PART, LARGE_ANN_INDEX_DIM) + "' LIMIT " + + std::to_string(SELECT_RES_NUM) + ";"; + std::shared_ptr resultSet = CreateIdxAndSelect(sqlSelect); + int columnIndex = 0; + size_t vectSize = 0; + ValueObject::FloatVector vecs = {}; + EXPECT_EQ(E_OK, resultSet->GetColumnIndex("repr", columnIndex)); + EXPECT_EQ(columnIndex, 1); + + ColumnType colType = ColumnType::TYPE_NULL; + EXPECT_EQ(E_OK, resultSet->GetColumnType(columnIndex, colType)); + EXPECT_EQ(ColumnType::TYPE_FLOAT32_ARRAY, colType); + + EXPECT_EQ(E_OK, resultSet->GetFloat32Array(columnIndex, vecs)); + EXPECT_EQ(E_OK, resultSet->GetSize(columnIndex, vectSize)); + EXPECT_EQ(vecs.size(), LARGE_ANN_INDEX_DIM); + EXPECT_EQ(sizeof(float) * LARGE_ANN_INDEX_DIM, vectSize); + + int idVal = 0; + EXPECT_EQ(E_OK, resultSet->GetColumnIndex("id", columnIndex)); + EXPECT_EQ(E_OK, resultSet->GetInt(columnIndex, idVal)); + + int ret = E_OK; + int resCnt = 0; + vecs.clear(); + while ((ret = resultSet->GoToNextRow() == E_OK)) { + EXPECT_EQ(E_OK, resultSet->GetColumnIndex("repr", columnIndex)); + EXPECT_EQ(1, columnIndex); // 1是向量的列 + + resultSet->GetColumnType(columnIndex, colType); + EXPECT_EQ(colType, ColumnType::TYPE_FLOAT32_ARRAY); + + EXPECT_EQ(E_COLUMN_OUT_RANGE, resultSet->GetColumnType(100, colType)); // 100是一个不存在的col, 所以预期返回NULL + + EXPECT_EQ(E_OK, resultSet->GetFloat32Array(columnIndex, vecs)); + EXPECT_EQ(E_OK, resultSet->GetSize(columnIndex, vectSize)); + EXPECT_EQ(vecs.size(), LARGE_ANN_INDEX_DIM); + EXPECT_EQ(sizeof(float) * LARGE_ANN_INDEX_DIM, vectSize); + resCnt++; + } + EXPECT_EQ(SELECT_RES_NUM - 1, resCnt); + EXPECT_EQ(E_OK, resultSet->Close()); + std::pair res = RdbExecuteRdTest::store->Execute("DROP TABLE test;"); + EXPECT_EQ(E_OK, res.first); +} + +/** +@tc.name: RdbStore_Execute_008 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_008, TestSize.Level1) +{ + std::string sqlSelect = "SELECT * FROM test;"; + std::shared_ptr resultSet = CreateIdxAndSelect(sqlSelect); + int columnIndex = 0; + size_t vectSize = 0; + ValueObject::FloatVector vecs = {}; + EXPECT_EQ(E_OK, resultSet->GetColumnIndex("repr", columnIndex)); + EXPECT_EQ(columnIndex, 1); + + ColumnType colType = ColumnType::TYPE_NULL; + EXPECT_EQ(E_OK, resultSet->GetColumnType(columnIndex, colType)); + EXPECT_EQ(ColumnType::TYPE_FLOAT32_ARRAY, colType); + + int idVal = 0; + EXPECT_EQ(E_OK, resultSet->GetColumnIndex("id", columnIndex)); + EXPECT_EQ(E_OK, resultSet->GetInt(columnIndex, idVal)); + + int ret = E_OK; + int resCnt = 1; + vecs.clear(); + EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); + while ((ret = resultSet->GoToNextRow() == E_OK)) { + EXPECT_EQ(E_OK, resultSet->GetColumnIndex("repr", columnIndex)); + EXPECT_EQ(1, columnIndex); // 1是向量的列, columnIndex期望是1 + + resultSet->GetColumnType(columnIndex, colType); + EXPECT_EQ(colType, ColumnType::TYPE_FLOAT32_ARRAY); + + EXPECT_EQ(E_OK, resultSet->GetFloat32Array(columnIndex, vecs)); + EXPECT_EQ(E_OK, resultSet->GetSize(columnIndex, vectSize)); + EXPECT_EQ(vecs.size(), LARGE_ANN_INDEX_DIM); + EXPECT_EQ(sizeof(float) * LARGE_ANN_INDEX_DIM, vectSize); + resCnt++; + } + EXPECT_EQ(10, resCnt); // 期待resCnt是10 + EXPECT_EQ(E_OK, resultSet->Close()); + std::pair res = RdbExecuteRdTest::store->Execute("DROP TABLE test;"); + EXPECT_EQ(E_OK, res.first); +} + +/** +@tc.name: RdbStore_Execute_009 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +constexpr uint32_t EXPEC_INSERT_CNT_FOR = 10; +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_009, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + + std::string sqlCreateTable = + "CREATE TABLE test(id int primary key, repr floatvector(" + std::to_string(LARGE_ANN_INDEX_DIM) + "));"; + std::string sqlCreateIndex = "CREATE INDEX diskann_l2_idx ON test USING GSIVFFLAT(repr L2);"; + std::string sqlSelect = "SELECT * FROM test;"; + + std::pair res = {}; + res = store->Execute(sqlCreateTable.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + std::pair trx = {}; + trx = store->BeginTrans(); + EXPECT_EQ(trx.first, E_OK); + + for (uint16_t i = 0; i < EXPEC_INSERT_CNT_FOR; i++) { + std::string sqlInsert = "INSERT INTO test VALUES(1000000" + std::to_string(i) + ", '" + + GetRandVector(MAX_INT_PART, LARGE_ANN_INDEX_DIM) + "');"; + res = store->Execute(sqlInsert.c_str(), {}, trx.second); + EXPECT_EQ(res.first, E_OK); + } + EXPECT_EQ(E_OK, store->Commit(trx.second)); + + res = store->Execute(sqlCreateIndex.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + std::shared_ptr resultSet = store->QueryByStep(sqlSelect.c_str(), std::vector()); + EXPECT_NE(resultSet, nullptr); + + int32_t resCnt = 0; + while (resultSet->GoToNextRow() == E_OK) { + resCnt++; + } + EXPECT_EQ(EXPEC_INSERT_CNT_FOR, resCnt); +} + +/** +@tc.name: RdbStore_Execute_010 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_010, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + + std::string sqlCreateTable = + "CREATE TABLE test(id int primary key, repr floatvector(" + std::to_string(LARGE_ANN_INDEX_DIM) + "));"; + std::string sqlCreateIndex = "CREATE INDEX diskann_l2_idx ON test USING GSIVFFLAT(repr L2);"; + std::string sqlSelect = "SELECT * FROM test;"; + + std::pair res = {}; + res = store->Execute(sqlCreateTable.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + for (uint16_t i = 0; i < 10; i++) { + std::string sqlInsert = "INSERT INTO test VALUES(1000000" + std::to_string(i) + ", '" + + GetRandVector(MAX_INT_PART, LARGE_ANN_INDEX_DIM) + "');"; + res = store->Execute(sqlInsert.c_str(), {}, 0); + EXPECT_EQ(res.first, E_OK); + } + + std::pair trx = {}; + trx = store->BeginTrans(); + EXPECT_EQ(trx.first, E_OK); + EXPECT_NE(trx.second, 0); + + for (uint16_t i = 0; i < 10; i++) { + std::string sqlDelete = "DELETE FROM test WHERE id = 1000000" + std::to_string(i) + ";"; + res = store->Execute(sqlDelete.c_str(), {}, trx.second); + EXPECT_EQ(res.first, E_OK); + } + + EXPECT_EQ(E_OK, store->Commit(trx.second)); + + std::shared_ptr resultSet = store->QueryByStep(sqlSelect.c_str(), std::vector()); + EXPECT_NE(resultSet, nullptr); + EXPECT_EQ(E_ROW_OUT_RANGE, resultSet->GoToNextRow()); +} + +/** +@tc.name: RdbStore_Execute_011 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_011, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + + std::string sqlCreateTable = "CREATE TABLE test(id int primary key, day int, repr floatvector(" + + std::to_string(LARGE_ANN_INDEX_DIM) + "));"; + std::string sqlCreateIndex = "CREATE INDEX diskann_l2_idx ON test USING GSIVFFLAT(repr L2);"; + std::string sqlSelect = "SELECT * FROM test;"; + + std::pair res = {}; + res = store->Execute(sqlCreateTable.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + for (uint16_t i = 0; i < 10; i++) { + std::string sqlInsert = "INSERT INTO test VALUES(1000000" + std::to_string(i) + ", 0, '" + + GetRandVector(MAX_INT_PART, LARGE_ANN_INDEX_DIM) + "');"; + res = store->Execute(sqlInsert.c_str(), {}, 0); + EXPECT_EQ(res.first, E_OK); + } + + std::pair trx = {}; + trx = store->BeginTrans(); + EXPECT_EQ(trx.first, E_OK); + EXPECT_NE(trx.second, 0); + + for (uint16_t i = 0; i < 10; i++) { + std::string sqlDelete = "UPDATE test SET day = 1 WHERE id = 1000000" + std::to_string(i) + ";"; + res = store->Execute(sqlDelete.c_str(), {}, trx.second); + EXPECT_EQ(res.first, E_OK); + } + + EXPECT_EQ(E_OK, store->Commit(trx.second)); + std::shared_ptr resultSet = store->QueryByStep(sqlSelect.c_str(), std::vector()); + EXPECT_NE(resultSet, nullptr); + + uint32_t resCnt = 0; + int64_t intVal = 0; + int columnIndex = 0; + ColumnType colType = ColumnType::TYPE_NULL; + + while (resultSet->GoToNextRow() == E_OK) { + std::vector colNames = {}; + resultSet->GetAllColumnNames(colNames); + EXPECT_STREQ("id", colNames[0].c_str()); + EXPECT_STREQ("day", colNames[1].c_str()); + EXPECT_STREQ("repr", colNames[2].c_str()); + + EXPECT_EQ(E_OK, resultSet->GetColumnIndex("day", columnIndex)); + EXPECT_EQ(1, columnIndex); // 1是day的列 + + EXPECT_EQ(E_OK, resultSet->GetColumnType(columnIndex, colType)); + EXPECT_EQ(colType, ColumnType::TYPE_INTEGER); + + EXPECT_EQ( + E_COLUMN_OUT_RANGE, resultSet->GetColumnType(100, colType)); // 100是一个不存在的col, 所以预期返回错误码 + EXPECT_EQ(colType, ColumnType::TYPE_INTEGER); // 值不会被更新 + + EXPECT_EQ(E_OK, resultSet->GetLong(columnIndex, intVal)); + EXPECT_EQ(1, intVal); + + resCnt++; + } +} + +/** +@tc.name: RdbStore_Execute_012 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_012, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + + std::string sqlCreateTable = + "CREATE TABLE test(id int primary key, repr floatvector(" + std::to_string(LARGE_ANN_INDEX_DIM) + "));"; + std::string sqlCreateIndex = "CREATE INDEX diskann_l2_idx ON test USING GSIVFFLAT(repr L2);"; + std::string sqlSelect = "SELECT * FROM test;"; + + std::pair res = {}; + res = store->Execute(sqlCreateTable.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + std::pair trx = {}; + trx = store->BeginTrans(); + EXPECT_EQ(trx.first, E_OK); + + for (uint16_t i = 0; i < EXPEC_INSERT_CNT_FOR; i++) { + std::string sqlInsert = "INSERT INTO test VALUES(1000000" + std::to_string(i) + ", '" + + GetRandVector(MAX_INT_PART, LARGE_ANN_INDEX_DIM) + "');"; + res = store->Execute(sqlInsert.c_str(), {}, trx.second); + EXPECT_EQ(res.first, E_OK); + } + EXPECT_EQ(E_OK, store->RollBack(trx.second)); + + res = store->Execute(sqlCreateIndex.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + std::shared_ptr resultSet = store->QueryByStep(sqlSelect.c_str(), std::vector()); + EXPECT_NE(resultSet, nullptr); + + int32_t resCnt = 0; + while (resultSet->GoToNextRow() == E_OK) { + resCnt++; + } + EXPECT_EQ(0, resCnt); +} + +/** +@tc.name: RdbStore_Execute_013 +@tc.desc: test RdbStore Execute in vector mode +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_013, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + + std::string sqlCreateTable = + "CREATE TABLE test(id int primary key, repr floatvector(" + std::to_string(LARGE_ANN_INDEX_DIM) + "));"; + std::string sqlCreateIndex = "CREATE INDEX diskann_l2_idx ON test USING GSIVFFLAT(repr L2);"; + std::string sqlSelect = "SELECT * FROM test;"; + + std::pair res = {}; + res = store->Execute(sqlCreateTable.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + std::pair trx = {}; + trx = store->BeginTrans(); + EXPECT_EQ(trx.first, E_OK); + + for (uint16_t i = 0; i < EXPEC_INSERT_CNT_FOR; i++) { + std::string sqlInsert = "INSERT INTO test VALUES(1000000" + std::to_string(i) + ", '" + + GetRandVector(MAX_INT_PART, LARGE_ANN_INDEX_DIM) + "');"; + res = store->Execute(sqlInsert.c_str(), {}, trx.second); + EXPECT_EQ(res.first, E_OK); + } + EXPECT_EQ(E_OK, store->RollBack(trx.second)); + + res = store->Execute(sqlCreateIndex.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + std::shared_ptr resultSet = store->QueryByStep(sqlSelect.c_str(), std::vector()); + EXPECT_NE(resultSet, nullptr); + + int32_t resCnt = 0; + while (resultSet->GoToNextRow() == E_OK) { + resCnt++; + } + EXPECT_EQ(0, resCnt); +} + +/** +@tc.name: RdbStore_Execute_014 +@tc.desc: test RdbStore Execute update in transaction +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_014, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + + std::string sqlCreateTable = "CREATE TABLE test(id int primary key, age int, repr floatvector(" + + std::to_string(LARGE_ANN_INDEX_DIM) + "));"; + std::string sqlCreateIndex = "CREATE INDEX diskann_l2_idx ON test USING GSIVFFLAT(repr L2);"; + std::string sqlSelect = "SELECT * FROM test;"; + + std::pair res = {}; + res = store->Execute(sqlCreateTable.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + for (uint16_t i = 0; i < 10; i++) { + std::string sqlInsert = "INSERT INTO test VALUES(1000000" + std::to_string(i) + ", " + std::to_string(i) + + ", '" + GetRandVector(MAX_INT_PART, LARGE_ANN_INDEX_DIM) + "');"; + res = store->Execute(sqlInsert.c_str(), {}, 0); + EXPECT_EQ(res.first, E_OK); + } + + std::pair trx = {}; + trx = store->BeginTrans(); + EXPECT_EQ(trx.first, E_OK); + EXPECT_NE(trx.second, 0); + + for (uint16_t i = 0; i < 10; i++) { + std::string sqlUpdate = "UPDATE test SET age = 1 WHERE id = 1000000" + std::to_string(i) + ";"; + res = store->Execute(sqlUpdate.c_str(), {}, trx.second); + EXPECT_EQ(res.first, E_OK); + } + + EXPECT_EQ(E_OK, store->Commit(trx.second)); + std::shared_ptr resultSet = store->QueryByStep(sqlSelect.c_str(), std::vector()); + int columnIndex = 0; + while (resultSet->GoToNextRow() == E_OK) { + std::vector colNames = {}; + resultSet->GetAllColumnNames(colNames); + EXPECT_STREQ("id", colNames[0].c_str()); + EXPECT_STREQ("age", colNames[1].c_str()); + EXPECT_STREQ("repr", colNames[2].c_str()); + + EXPECT_EQ(E_OK, resultSet->GetColumnIndex("age", columnIndex)); + EXPECT_EQ(1, columnIndex); // 1是age的列 + int result; + EXPECT_EQ(E_OK, resultSet->GetInt(columnIndex, result)); + EXPECT_EQ(result, 1); + } +} + +/** +@tc.name: RdbStore_Execute_014 +@tc.desc: test RdbStore Execute Repeatly Get Transaction +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_015, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + + std::string sqlCreateTable = "CREATE TABLE test2 (id INTEGER PRIMARY KEY, repr INTEGER);"; + std::string sqlSelect = "SELECT * FROM test2;"; + + std::pair res = {}; + res = store->Execute(sqlCreateTable.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + for (uint32_t i = 0; i < 10; i++) { + std::pair trx = {}; + trx = store->BeginTrans(); + EXPECT_EQ(trx.first, E_OK); + std::string sqlInsert = "INSERT INTO test2 VALUES(" + std::to_string(i) + ", 1);"; + res = store->Execute(sqlInsert.c_str(), {}, trx.second); + EXPECT_EQ(res.first, E_OK); + EXPECT_EQ(E_OK, store->Commit(trx.second)); + } + + std::shared_ptr resultSet = store->QueryByStep(sqlSelect.c_str(), std::vector()); + EXPECT_NE(resultSet, nullptr); + + int32_t resCnt = 0; + while (resultSet->GoToNextRow() == E_OK) { + int rowIdx = 0; + resultSet->GetRowIndex(rowIdx); + EXPECT_EQ(resCnt, rowIdx); + resCnt++; + } + EXPECT_EQ(10, resCnt); +} + +/** +@tc.name: RdbStore_Execute_016 +@tc.desc: test RdbStore Execute Repeatly Get Transaction +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_016, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + std::string sqlCreateTable = "CREATE TABLE IF NOT EXISTS test1 (docId Text, str Text, repr floatvector(4));"; + std::string sqlCreateIdx = "CREATE INDEX test_idx ON test1 USING GSIVFFLAT(repr L2);"; + std::string sqlSelect = "SELECT * FROM test1 ORDER BY repr <-> '[1.0, 2.0, 3.0, 4.0]' LIMIT 2;"; + + std::pair res = store->Execute(sqlCreateTable.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + res = store->Execute(sqlCreateIdx.c_str(), {}); + EXPECT_EQ(res.first, E_OK); + + std::vector> vectorSamples = {{1.0, 2.0, 3.0, 4.0}, {10, 20, 30, 40}, {100, 200, 300, 400}}; + + for (uint32_t i = 0; i < vectorSamples.size(); i++) { + std::pair trx = {}; + trx = store->BeginTrans(); + EXPECT_EQ(trx.first, E_OK); + std::string sqlInsert = "insert into test1 values('" + std::to_string(i) + "', ?, ?);"; + ValueObject floatObj = ValueObject(vectorSamples[i]); + ValueObject::FloatVector vector = {}; + EXPECT_EQ(floatObj.GetVecs(vector), E_OK); + EXPECT_EQ(vectorSamples[i].size(), vector.size()); + for (size_t j = 0; j < vector.size(); j++) { + EXPECT_FLOAT_EQ(vectorSamples[i][j], vector[j]); + } + + res = store->Execute(sqlInsert.c_str(), {ValueObject(std::string("textVal")), floatObj}, trx.second); + EXPECT_EQ(res.first, E_OK); + EXPECT_EQ(E_OK, store->Commit(trx.second)); + } + + std::shared_ptr resultSet = store->QueryByStep(sqlSelect.c_str(), std::vector()); + EXPECT_NE(resultSet, nullptr); + + int32_t resCnt = 0; + while (resultSet->GoToNextRow() == E_OK) { + std::string primaryStrVal = ""; + std::string textStrVal = ""; + ValueObject::FloatVector floatVector = {}; + resultSet->GetString(0, primaryStrVal); // 0 is the index of primary String column in select projection + resultSet->GetString(1, textStrVal); // 1 is the index of TEXT column in select projection + resultSet->GetFloat32Array(2, floatVector); // 2 is the index of vector column in select projection + EXPECT_STREQ(std::to_string(resCnt).c_str(), primaryStrVal.c_str()); + EXPECT_STREQ("textVal", textStrVal.c_str()); + EXPECT_EQ(vectorSamples[resCnt].size(), floatVector.size()); + for (size_t i = 0; i < floatVector.size(); i++) { + EXPECT_FLOAT_EQ(vectorSamples[resCnt][i], floatVector[i]); + } + resCnt++; + } + EXPECT_EQ(2, resCnt); // Expect 2 result due to limit 2 +} + +/** +@tc.name: RdbStore_Execute_017 +@tc.desc: test RdbStore Execute Getting or Setting version +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_017, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + int versionToGet = 0; + int versionToSet = 1; + EXPECT_EQ(E_OK, store->SetVersion(versionToSet)); + EXPECT_EQ(E_OK, store->GetVersion(versionToGet)); + EXPECT_EQ(versionToGet, versionToSet); + + std::string sqlPragmaSetVersion = "PRAGMA user_version = 3"; + std::pair res = {}; + res = store->Execute(sqlPragmaSetVersion.c_str(), {}, 0); + EXPECT_EQ(res.first, E_OK); + EXPECT_EQ(E_OK, store->GetVersion(versionToGet)); + EXPECT_EQ(versionToGet, 3); // 3 is set by sql + + sqlPragmaSetVersion = "PRAGMA user_version = 4;"; + res = store->Execute(sqlPragmaSetVersion.c_str(), {}, 0); + EXPECT_EQ(res.first, E_OK); + EXPECT_EQ(E_OK, store->GetVersion(versionToGet)); + EXPECT_EQ(versionToGet, 4); // 4 is set by sql + + sqlPragmaSetVersion = "PRAGMA user_version = 35678"; + res = store->Execute(sqlPragmaSetVersion.c_str(), {}, 0); + EXPECT_EQ(res.first, E_OK); + EXPECT_EQ(E_OK, store->GetVersion(versionToGet)); + EXPECT_EQ(versionToGet, 35678); // 35678 is set by sql + + sqlPragmaSetVersion = "PRAGMA user_version = asdfds"; + res = store->Execute(sqlPragmaSetVersion.c_str(), {}, 0); + EXPECT_EQ(res.first, E_INCORRECT_SQL); + + sqlPragmaSetVersion = "PRAGMA user_version = ;"; + res = store->Execute(sqlPragmaSetVersion.c_str(), {}, 0); + EXPECT_EQ(res.first, E_INCORRECT_SQL); + + sqlPragmaSetVersion = "PRAGMA user_version = 456 "; + res = store->Execute(sqlPragmaSetVersion.c_str(), {}, 0); + EXPECT_EQ(res.first, E_OK); + EXPECT_EQ(E_OK, store->GetVersion(versionToGet)); + EXPECT_EQ(versionToGet, 456); // 456 is set by sql + + sqlPragmaSetVersion = "PRAGMA user_version = 456 1231 "; + res = store->Execute(sqlPragmaSetVersion.c_str(), {}, 0); + EXPECT_EQ(res.first, E_INCORRECT_SQL); + + sqlPragmaSetVersion = "PRAGMA user_version = 456 1asdf231 "; + res = store->Execute(sqlPragmaSetVersion.c_str(), {}, 0); + EXPECT_EQ(res.first, E_INCORRECT_SQL); +} + +/** +@tc.name: RdbStore_Execute_018 +@tc.desc: test RdbStore create encrypted db from non-encrypted db +@tc.type: FUNC +*/ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_018, TestSize.Level1) +{ + RdbExecuteRdTest::store = nullptr; + bool isOriginDbEncrypt = GetParam(); + + RdbStoreConfig config(RdbExecuteRdTest::databaseName); + config.SetIsVector(true); + config.SetEncryptStatus(!isOriginDbEncrypt); + ExecuteTestOpenRdCallback helper; + int errCode = E_OK; + RdbExecuteRdTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + // open encrypted-db in un-encrypted mode is not allowed + // open un-encrypted db in encrypted-db is allowed + EXPECT_TRUE((isOriginDbEncrypt && RdbExecuteRdTest::store == nullptr) || + (!isOriginDbEncrypt && RdbExecuteRdTest::store != nullptr)); + if (!isOriginDbEncrypt) { + RdbExecuteRdTest::store = nullptr; + config.SetEncryptStatus(false); // open encrypted-db update from un-encrypt in un-encrypted mode is not allowed + RdbExecuteRdTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_EQ(store, nullptr); + } +} diff --git a/relational_store/test/native/rdb/unittest/rdb_store_impl_test.cpp b/relational_store/test/native/rdb/unittest/rdb_store_impl_test.cpp index aad81faa..ef58eb0b 100644 --- a/relational_store/test/native/rdb/unittest/rdb_store_impl_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_store_impl_test.cpp @@ -913,7 +913,7 @@ HWTEST_F(RdbStoreImplTest, CreateTransaction_003, TestSize.Level1) } entries.push_back(std::move(trans)); } - ASSERT_EQ(errCode, E_CON_OVER_LIMIT); + ASSERT_EQ(errCode, E_DATABASE_BUSY); ASSERT_EQ(entries.size(), MAX_TRANS); } diff --git a/relational_store/test/native/rdb/unittest/rdb_trans_db_test.cpp b/relational_store/test/native/rdb/unittest/rdb_trans_db_test.cpp index 052e5fcb..ee627051 100644 --- a/relational_store/test/native/rdb/unittest/rdb_trans_db_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_trans_db_test.cpp @@ -1132,4 +1132,66 @@ HWTEST_F(RdbTransDBTest, QueryByStep_ThreadSafe_001, TestSize.Level1) threads[i] = nullptr; } } + +/* * + * @tc.name: ExecuteForLastInsertRowId_001 + * @tc.desc: INSERT OR IGNORE INTO TEST(id, name) VALUES(?,?) + * @tc.type: FUNC + */ +HWTEST_F(RdbTransDBTest, ExecuteForLastInsertRowId_001, TestSize.Level1) +{ + int64_t rowId = 0; + auto errCode = + transDB_->ExecuteForLastInsertedRowId(rowId, "INSERT INTO TEST(id, name) VALUES (?,?)", { 100, "xiaohong" }); + ASSERT_EQ(errCode, E_OK); + ASSERT_EQ(rowId, 1); + errCode = transDB_->ExecuteForLastInsertedRowId(rowId, "INSERT OR IGNORE INTO TEST(id, name) VALUES (?,?)", + { 100, "xiaoming" }); + ASSERT_EQ(errCode, E_OK); + ASSERT_EQ(rowId, -1); + auto resultSet = transDB_->QueryByStep("select * from TEST where id == ?", RdbStore::Values{ 100 }); + ASSERT_NE(resultSet, nullptr); + errCode = resultSet->GoToNextRow(); + ASSERT_EQ(errCode, E_OK); + RowEntity rowEntity; + errCode = resultSet->GetRow(rowEntity); + ASSERT_EQ(errCode, E_OK); + auto row = rowEntity.Steal(); + ASSERT_TRUE(row["id"] == ValueObject(100)); + ASSERT_TRUE(row["name"] == ValueObject("xiaohong")); + int32_t count = -1; + errCode = resultSet->GetRowCount(count); + ASSERT_EQ(errCode, E_OK); + ASSERT_EQ(count, 1); +} + +/* * + * @tc.name: ExecuteForChangedRowCount_001 + * @tc.desc: UPDATE TEST SET id=?, name=? + * @tc.type: FUNC + */ +HWTEST_F(RdbTransDBTest, ExecuteForChangedRowCount_001, TestSize.Level1) +{ + auto [errCode, value] = transDB_->Execute("INSERT INTO TEST(id, name) VALUES (?,?)", { 100, "xiaohong" }); + ASSERT_EQ(errCode, E_OK); + ASSERT_EQ(value, ValueObject(1)); + int64_t changedRow = 0; + errCode = transDB_->ExecuteForChangedRowCount(changedRow, "UPDATE TEST SET id=?, name=?", { 100, "xiaoming" }); + ASSERT_EQ(errCode, E_OK); + ASSERT_EQ(changedRow, 1); + auto resultSet = transDB_->QueryByStep("select * from TEST where id == ?", RdbStore::Values{ 100 }); + ASSERT_NE(resultSet, nullptr); + errCode = resultSet->GoToNextRow(); + ASSERT_EQ(errCode, E_OK); + RowEntity rowEntity; + errCode = resultSet->GetRow(rowEntity); + ASSERT_EQ(errCode, E_OK); + auto row = rowEntity.Steal(); + ASSERT_TRUE(row["id"] == ValueObject(100)); + ASSERT_TRUE(row["name"] == ValueObject("xiaoming")); + int32_t count = -1; + errCode = resultSet->GetRowCount(count); + ASSERT_EQ(errCode, E_OK); + ASSERT_EQ(count, 1); +} } // namespace Test diff --git a/relational_store/test/native/rdb/unittest/transaction_test.cpp b/relational_store/test/native/rdb/unittest/transaction_test.cpp index c4e325e7..177fab5c 100644 --- a/relational_store/test/native/rdb/unittest/transaction_test.cpp +++ b/relational_store/test/native/rdb/unittest/transaction_test.cpp @@ -94,52 +94,45 @@ HWTEST_F(TransactionTest, RdbStore_Transaction_001, TestSize.Level1) std::shared_ptr &store = TransactionTest::store_; auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); - EXPECT_EQ(ret, E_OK); - EXPECT_NE(transaction, nullptr); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); auto result = transaction->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[0])); - EXPECT_EQ(result.first, E_OK); - EXPECT_EQ(1, result.second); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(1, result.second); result = transaction->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[1])); - EXPECT_EQ(result.first, E_OK); - EXPECT_EQ(2, result.second); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(2, result.second); result = store->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[2]), RdbStore::NO_ACTION); - EXPECT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.first, E_SQLITE_BUSY); auto resultSet = transaction->QueryByStep("SELECT * FROM test"); - EXPECT_NE(resultSet, nullptr); - if (resultSet != nullptr) { - int32_t rowCount{}; - ret = resultSet->GetRowCount(rowCount); - EXPECT_EQ(ret, E_OK); - EXPECT_EQ(rowCount, 2); - } + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + ASSERT_EQ(ret, E_OK); + ASSERT_EQ(rowCount, 2); ret = transaction->Commit(); - EXPECT_EQ(ret, E_OK); + ASSERT_EQ(ret, E_OK); - if (resultSet != nullptr) { - ValueObject value; - ret = resultSet->Get(0, value); - EXPECT_EQ(ret, E_ALREADY_CLOSED); - } + ValueObject value; + ret = resultSet->Get(0, value); + ASSERT_EQ(ret, E_ALREADY_CLOSED); result = store->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[2]), RdbStore::NO_ACTION); - EXPECT_EQ(result.first, E_OK); - EXPECT_EQ(3, result.second); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(3, result.second); result = transaction->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[0])); - EXPECT_EQ(result.first, E_ALREADY_CLOSED); + ASSERT_EQ(result.first, E_ALREADY_CLOSED); resultSet = store->QueryByStep("SELECT * FROM test"); - EXPECT_NE(resultSet, nullptr); - if (resultSet != nullptr) { - int32_t rowCount{}; - resultSet->GetRowCount(rowCount); - EXPECT_EQ(rowCount, 3); - } + ASSERT_NE(resultSet, nullptr); + resultSet->GetRowCount(rowCount); + EXPECT_EQ(rowCount, 3); } /** @@ -152,42 +145,247 @@ HWTEST_F(TransactionTest, RdbStore_Transaction_002, TestSize.Level1) std::shared_ptr &store = TransactionTest::store_; auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); - EXPECT_EQ(ret, E_OK); - EXPECT_NE(transaction, nullptr); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); auto result = transaction->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[0])); - EXPECT_EQ(result.first, E_OK); - EXPECT_EQ(1, result.second); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(1, result.second); result = transaction->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[1])); - EXPECT_EQ(result.first, E_OK); - EXPECT_EQ(2, result.second); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(2, result.second); ret = transaction->Rollback(); - EXPECT_EQ(ret, E_OK); + ASSERT_EQ(ret, E_OK); auto resultSet = store->QueryByStep("SELECT * FROM test"); - EXPECT_NE(resultSet, nullptr); - if (resultSet != nullptr) { - int32_t rowCount{}; - ret = resultSet->GetRowCount(rowCount); - EXPECT_EQ(ret, E_OK); - EXPECT_EQ(rowCount, 0); - } + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + ASSERT_EQ(ret, E_OK); + ASSERT_EQ(rowCount, 0); result = store->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[2]), RdbStore::NO_ACTION); - EXPECT_EQ(result.first, E_OK); - EXPECT_EQ(3, result.second); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(3, result.second); result = transaction->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[0])); - EXPECT_EQ(result.first, E_ALREADY_CLOSED); + ASSERT_EQ(result.first, E_ALREADY_CLOSED); resultSet = store->QueryByStep("SELECT * FROM test"); - EXPECT_NE(resultSet, nullptr); - if (resultSet != nullptr) { - int32_t rowCount{}; - ret = resultSet->GetRowCount(rowCount); - EXPECT_EQ(ret, E_OK); - EXPECT_EQ(rowCount, 1); - } + ASSERT_NE(resultSet, nullptr); + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 1); +} + +/** + * @tc.name: RdbStore_Transaction_003 + * @tc.desc: batchInsert + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_003, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + Transaction::Rows rows { + UTUtils::SetRowData(UTUtils::g_rowData[0]), + UTUtils::SetRowData(UTUtils::g_rowData[1]), + UTUtils::SetRowData(UTUtils::g_rowData[2]), + }; + auto result = transaction->BatchInsert("test", rows); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 3); + + ret = transaction->Commit(); + ASSERT_EQ(ret, E_OK); + + auto resultSet = store->QueryByStep("SELECT * FROM test"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 3); +} + +/** + * @tc.name: RdbStore_Transaction_004 + * @tc.desc: batchInsert + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_004, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + Transaction::RefRows rows; + rows.Put(UTUtils::SetRowData(UTUtils::g_rowData[0])); + rows.Put(UTUtils::SetRowData(UTUtils::g_rowData[1])); + rows.Put(UTUtils::SetRowData(UTUtils::g_rowData[2])); + + auto result = transaction->BatchInsert("test", rows); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 3); + + ret = transaction->Commit(); + ASSERT_EQ(ret, E_OK); + + auto resultSet = store->QueryByStep("SELECT * FROM test"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 3); +} + +/** + * @tc.name: RdbStore_Transaction_005 + * @tc.desc: Update + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_005, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + auto result = transaction->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[0])); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 1); + + result = transaction->Update("test", UTUtils::SetRowData(UTUtils::g_rowData[1]), "id=1"); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 1); + + auto resultSet = transaction->QueryByStep("SELECT * FROM test"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + ASSERT_EQ(ret, E_OK); + ASSERT_EQ(rowCount, 1); + ret = resultSet->GoToFirstRow(); + ASSERT_EQ(ret, E_OK); + int32_t columnIndex{}; + ret = resultSet->GetColumnIndex("id", columnIndex); + ASSERT_EQ(ret, E_OK); + int32_t id{}; + ret = resultSet->GetInt(columnIndex, id); + ASSERT_EQ(ret, E_OK); + ASSERT_EQ(id, 2); + + AbsRdbPredicates predicates("test"); + predicates.EqualTo("id", ValueObject(2)); + result = transaction->Update(UTUtils::SetRowData(UTUtils::g_rowData[2]), predicates); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 1); + + ret = transaction->Commit(); + ASSERT_EQ(ret, E_OK); + + resultSet = store->QueryByStep("SELECT * FROM test"); + ASSERT_NE(resultSet, nullptr); + ret = resultSet->GetRowCount(rowCount); + ASSERT_EQ(ret, E_OK); + ASSERT_EQ(rowCount, 1); + ret = resultSet->GoToFirstRow(); + ASSERT_EQ(ret, E_OK); + resultSet->GetColumnIndex("id", columnIndex); + ret = resultSet->GetInt(columnIndex, id); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(id, 3); +} + +/** + * @tc.name: RdbStore_Transaction_006 + * @tc.desc: Delete + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_006, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + Transaction::RefRows rows; + rows.Put(UTUtils::SetRowData(UTUtils::g_rowData[0])); + rows.Put(UTUtils::SetRowData(UTUtils::g_rowData[1])); + rows.Put(UTUtils::SetRowData(UTUtils::g_rowData[2])); + + auto result = transaction->BatchInsert("test", rows); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 3); + + result = transaction->Delete("test", "id=1"); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 1); + + AbsRdbPredicates predicates("test"); + predicates.EqualTo("id", ValueObject(2)); + result = transaction->Delete(predicates); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 1); + + ret = transaction->Commit(); + ASSERT_EQ(ret, E_OK); + + auto resultSet = store->QueryByStep("SELECT * FROM test"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + ASSERT_EQ(ret, E_OK); + ASSERT_EQ(rowCount, 1); + ret = resultSet->GoToFirstRow(); + ASSERT_EQ(ret, E_OK); + int32_t columnIndex{}; + resultSet->GetColumnIndex("id", columnIndex); + int32_t id{}; + ret = resultSet->GetInt(columnIndex, id); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(id, 3); +} + +/** + * @tc.name: RdbStore_Transaction_007 + * @tc.desc: Execute + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_007, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + auto res = transaction->Execute( + "CREATE TABLE IF NOT EXISTS test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + Transaction::Row row; + row.Put("id", 1); + row.Put("name", "Jim"); + auto result = transaction->Insert("test1", row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 1); + + ret = transaction->Commit(); + ASSERT_EQ(ret, E_OK); + + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 1); } -- Gitee