Add attach api

Signed-off-by: changjiaxing <changjiaxing2@huawei.com>
Change-Id: Ica26d9c262082021e0478e31e108fc2c4a7217a0
This commit is contained in:
changjiaxing 2024-03-21 21:32:33 +08:00
parent 001e090220
commit 0a7eeac889
39 changed files with 1705 additions and 692 deletions

View File

@ -29,13 +29,13 @@ AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBinaryOperators: false
BreakBeforeBraces: Custom

View File

@ -41,11 +41,11 @@ int32_t Convert2Value(napi_env env, napi_value input, ExtraData &output)
if (status != napi_ok || type != napi_object) {
return napi_invalid_arg;
}
int32_t result = GET_PROPERTY(env, input, output, eventId);
int32_t result = GetNamedProperty(env, input, "eventId", output.eventId);
if (result != napi_ok) {
return napi_invalid_arg;
}
return GET_PROPERTY(env, input, output, extraData);
return GetNamedProperty(env, input, "extraData", output.extraData);
}
template<>
@ -57,18 +57,18 @@ int32_t Convert2Value(napi_env env, napi_value input, Participant &output)
LOG_DEBUG("napi_typeof failed status = %{public}d type = %{public}d", status, type);
return napi_invalid_arg;
}
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, input, output, identity), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetOptionalValue(env, input, "role", output.role), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "identity", output.identity), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "role", output.role, true), napi_invalid_arg);
if (output.role < CloudData::Role::ROLE_NIL || output.role >= CloudData::Role::ROLE_BUTT) {
return napi_invalid_arg;
}
NAPI_CALL_RETURN_ERR(GetOptionalValue(env, input, "state", output.state), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "state", output.state, true), napi_invalid_arg);
if (output.state < CloudData::Confirmation::CFM_NIL ||
output.state >= CloudData::Confirmation::CFM_BUTT) {
return napi_invalid_arg;
}
NAPI_CALL_RETURN_ERR(GetOptionalValue(env, input, "privilege", output.privilege), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetOptionalValue(env, input, "attachInfo", output.attachInfo), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "privilege", output.privilege, true), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "attachInfo", output.attachInfo, true), napi_invalid_arg);
return napi_ok;
}
@ -81,11 +81,11 @@ int32_t Convert2Value(napi_env env, napi_value input, Privilege &output)
LOG_DEBUG("napi_typeof failed status = %{public}d type = %{public}d", status, type);
return napi_invalid_arg;
}
NAPI_CALL_RETURN_ERR(GetOptionalValue(env, input, "writable", output.writable), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetOptionalValue(env, input, "readable", output.readable), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetOptionalValue(env, input, "creatable", output.creatable), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetOptionalValue(env, input, "deletable", output.deletable), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetOptionalValue(env, input, "shareable", output.shareable), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "writable", output.writable, true), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "readable", output.readable, true), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "creatable", output.creatable, true), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "deletable", output.deletable, true), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "shareable", output.shareable, true), napi_invalid_arg);
return napi_ok;
}
@ -101,17 +101,14 @@ int32_t Convert2Value(napi_env env, napi_value jsValue, Asset &output)
return napi_invalid_arg;
}
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, name), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, uri), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, createTime), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, modifyTime), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, size), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, path), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "name", output.name), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "uri", output.uri), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "createTime", output.createTime), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "modifyTime", output.modifyTime), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "modifyTime", output.size), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "path", output.path), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "status", output.status, true), napi_invalid_arg);
output.hash = output.modifyTime + "_" + output.size;
auto jsStatus = GetNamedProperty(env, jsValue, "status");
if (jsStatus != nullptr) {
Convert2ValueExt(env, jsStatus, output.status);
}
if (output.status != Asset::STATUS_DELETE) {
output.status = Asset::STATUS_UNKNOWN;
}

View File

@ -18,8 +18,8 @@
#include <iostream>
#include <string>
#include "ability.h"
#include "napi/native_api.h"
#include "ability.h"
#include "napi/native_common.h"
#include "napi/native_node_api.h"
#include "napi_base_context.h"

View File

@ -16,14 +16,18 @@
#ifndef DISTRIBUTEDDATAMGR_APPDATAMGR_JSUTILS_H
#define DISTRIBUTEDDATAMGR_APPDATAMGR_JSUTILS_H
#include <stdint.h>
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
#include <optional>
#include "napi/native_api.h"
#include "napi/native_common.h"
#include "napi/native_node_api.h"
@ -31,35 +35,24 @@
namespace OHOS {
namespace AppDataMgrJsKit {
namespace JSUtils {
constexpr int OK = 0;
constexpr int ERR = -1;
constexpr uint32_t ASYNC_RST_SIZE = 2;
constexpr uint32_t DEFAULT_VALUE_LENGTH = 1024;
constexpr uint32_t MAX_VALUE_LENGTH = 1024 * 1024 * 8; // the max length of all kand of out string value
constexpr uint32_t SYNC_RESULT_ELEMENT_NUM = 2;
static constexpr int OK = 0;
static constexpr int ERR = -1;
static constexpr uint32_t ASYNC_RST_SIZE = 2;
static constexpr uint32_t DEFAULT_VALUE_LENGTH = 1024;
static constexpr uint32_t MAX_VALUE_LENGTH = 1024 * 1024 * 8; // the max length of all kand of out string value
static constexpr uint32_t SYNC_RESULT_ELEMENT_NUM = 2;
struct JsFeatureSpace {
const char* spaceName;
const char* nameBase64;
const char *spaceName;
const char *nameBase64;
bool isComponent;
};
#ifndef ADD_JS_PROPERTY
#define ADD_JS_PROPERTY(env, object, value, member) \
napi_set_named_property((env), (object), #member, Convert2JSValue((env), (value).member))
#endif
#ifndef GET_PROPERTY
#define GET_PROPERTY(env, object, value, member) \
Convert2Value((env), GetNamedProperty((env), (object), #member), (value).member)
#endif
napi_value GetNamedProperty(napi_env env, napi_value object, const char *name);
std::pair<int32_t, napi_value> GetOptionalNamedProperty(napi_env env, napi_value input, const char *name);
int32_t Convert2ValueExt(napi_env env, napi_value jsValue, uint32_t &output);
int32_t Convert2ValueExt(napi_env env, napi_value jsValue, int32_t &output);
int32_t Convert2ValueExt(napi_env env, napi_value jsValue, int64_t &output);
int32_t Convert2Value(napi_env env, napi_value jsValue, napi_value &output);
int32_t Convert2Value(napi_env env, napi_value jsValue, bool &output);
int32_t Convert2Value(napi_env env, napi_value jsValue, double &output);
int32_t Convert2Value(napi_env env, napi_value jsValue, int64_t &output);
@ -77,7 +70,7 @@ template<typename T>
int32_t Convert2Value(napi_env env, napi_value jsValue, T &output);
template<typename T>
int32_t Convert2ValueExt(napi_env env, napi_value jsValue, T &output);
int32_t Convert2ValueExt(napi_env env, napi_value jsValue, T &output);
template<typename T>
int32_t Convert2Value(napi_env env, napi_value jsValue, std::vector<T> &value);
@ -129,22 +122,6 @@ napi_value Convert2JSValue(napi_env env, const std::variant<Types...> &value);
template<typename T>
std::string ToString(const T &key);
template <typename T>
int32_t GetOptionalValue(napi_env env, napi_value in, const char *name, T& out)
{
auto [status, value] = GetOptionalNamedProperty(env, in, name);
if (status != napi_ok) {
return status;
}
if (value == nullptr) {
return napi_ok;
}
if (std::is_same_v<T, int32_t>) {
return JSUtils::Convert2ValueExt(env, value, out);
}
return JSUtils::Convert2Value(env, value, out);
}
template<typename K>
std::enable_if_t<!std::is_same_v<K, std::string>, std::string> ConvertMapKey(const K &key)
{
@ -190,6 +167,36 @@ napi_value GetJSValue(napi_env env, const T &value)
}
return GetJSValue<T, Types...>(env, value);
}
std::pair<napi_status, napi_value> GetInnerValue(napi_env env, napi_value in, const std::string &prop, bool optional);
template<typename T>
inline std::enable_if_t<std::is_same_v<T, int32_t> || std::is_same_v<T, uint32_t>, int32_t> GetNamedProperty(
napi_env env, napi_value in, const std::string &prop, T &value, bool optional = false)
{
auto [status, jsValue] = GetInnerValue(env, in, prop, optional);
if (jsValue == nullptr) {
return status;
}
return Convert2ValueExt(env, jsValue, value);
};
template<typename T>
inline std::enable_if_t<!std::is_same_v<T, int32_t> && !std::is_same_v<T, uint32_t>, int32_t> GetNamedProperty(
napi_env env, napi_value in, const std::string &prop, T &value, bool optional = false)
{
auto [status, jsValue] = GetInnerValue(env, in, prop, optional);
if (jsValue == nullptr) {
return status;
}
return Convert2Value(env, jsValue, value);
};
template<typename T>
inline int32_t SetNamedProperty(napi_env env, napi_value in, const std::string &prop, T value)
{
return napi_set_named_property(env, in, prop.c_str(), Convert2JSValue(env, value));
};
} // namespace JSUtils
template<typename T>

View File

@ -14,6 +14,7 @@
*/
#include "js_utils.h"
#include "js_native_api_types.h"
#include "logger.h"
#include <cstring>
using namespace OHOS::Rdb;
@ -53,29 +54,24 @@ const std::optional<JSUtils::JsFeatureSpace> JSUtils::GetJsFeatureSpace(const st
return std::nullopt;
}
napi_value JSUtils::GetNamedProperty(napi_env env, napi_value object, const char *name)
{
napi_value jsItem = nullptr;
napi_get_named_property(env, object, name, &jsItem);
return jsItem;
}
std::pair<int32_t, napi_value> JSUtils::GetOptionalNamedProperty(napi_env env, napi_value input, const char *name)
std::pair<napi_status, napi_value> JSUtils::GetInnerValue(
napi_env env, napi_value in, const std::string& prop, bool optional)
{
bool hasProp = false;
napi_status status = napi_has_named_property(env, input, name, &hasProp);
napi_status status = napi_has_named_property(env, in, prop.c_str(), &hasProp);
if (status != napi_ok) {
return std::make_pair(napi_generic_failure, nullptr);
}
if (!hasProp) {
return std::make_pair(napi_ok, nullptr);
status = optional ? napi_ok : napi_generic_failure;
return std::make_pair(status, nullptr);
}
napi_value inner = nullptr;
status = napi_get_named_property(env, input, name, &inner);
status = napi_get_named_property(env, in, prop.c_str(), &inner);
if (status != napi_ok || inner == nullptr) {
return std::make_pair(napi_generic_failure, nullptr);
}
if (JSUtils::IsNull(env, inner)) {
if (optional && JSUtils::IsNull(env, inner)) {
return std::make_pair(napi_ok, nullptr);
}
return std::make_pair(napi_ok, inner);
@ -122,6 +118,12 @@ int32_t JSUtils::Convert2ValueExt(napi_env env, napi_value jsValue, int32_t &out
return status;
}
int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, napi_value &output)
{
output = jsValue;
return napi_ok;
}
int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, bool &output)
{
napi_valuetype type = napi_undefined;
@ -152,7 +154,7 @@ int32_t JSUtils::Convert2ValueExt(napi_env env, napi_value jsValue, int64_t &out
status = napi_get_value_int64(env, jsValue, &output);
if (status != napi_ok) {
LOG_DEBUG("napi_get_value_int32 failed, status = %{public}d", status);
LOG_DEBUG("napi_get_value_int64 failed, status = %{public}d", status);
return status;
}
return status;

View File

@ -33,14 +33,13 @@ int32_t Convert2Value(napi_env env, napi_value jsValue, Asset &output)
return napi_invalid_arg;
}
NAPI_CALL_BASE(env, Convert2ValueExt(env, GetNamedProperty(env, jsValue, "version"), output.version),
napi_invalid_arg);
NAPI_CALL_BASE(env, GET_PROPERTY(env, jsValue, output, name), napi_invalid_arg);
NAPI_CALL_BASE(env, GET_PROPERTY(env, jsValue, output, uri), napi_invalid_arg);
NAPI_CALL_BASE(env, GET_PROPERTY(env, jsValue, output, createTime), napi_invalid_arg);
NAPI_CALL_BASE(env, GET_PROPERTY(env, jsValue, output, modifyTime), napi_invalid_arg);
NAPI_CALL_BASE(env, GET_PROPERTY(env, jsValue, output, size), napi_invalid_arg);
NAPI_CALL_BASE(env, GET_PROPERTY(env, jsValue, output, hash), napi_invalid_arg);
NAPI_CALL_BASE(env, GetNamedProperty(env, jsValue, "version", output.version), napi_invalid_arg);
NAPI_CALL_BASE(env, GetNamedProperty(env, jsValue, "name", output.name), napi_invalid_arg);
NAPI_CALL_BASE(env, GetNamedProperty(env, jsValue, "uri", output.uri), napi_invalid_arg);
NAPI_CALL_BASE(env, GetNamedProperty(env, jsValue, "createTime", output.createTime), napi_invalid_arg);
NAPI_CALL_BASE(env, GetNamedProperty(env, jsValue, "modifyTime", output.modifyTime), napi_invalid_arg);
NAPI_CALL_BASE(env, GetNamedProperty(env, jsValue, "size", output.size), napi_invalid_arg);
NAPI_CALL_BASE(env, GetNamedProperty(env, jsValue, "hash", output.hash), napi_invalid_arg);
return napi_ok;
}
@ -49,13 +48,13 @@ napi_value Convert2JSValue(napi_env env, const Asset &value)
{
napi_value object = nullptr;
NAPI_CALL_BASE(env, napi_create_object(env, &object), object);
NAPI_CALL_BASE(env, ADD_JS_PROPERTY(env, object, value, version), object);
NAPI_CALL_BASE(env, ADD_JS_PROPERTY(env, object, value, name), object);
NAPI_CALL_BASE(env, ADD_JS_PROPERTY(env, object, value, uri), object);
NAPI_CALL_BASE(env, ADD_JS_PROPERTY(env, object, value, createTime), object);
NAPI_CALL_BASE(env, ADD_JS_PROPERTY(env, object, value, modifyTime), object);
NAPI_CALL_BASE(env, ADD_JS_PROPERTY(env, object, value, size), object);
NAPI_CALL_BASE(env, ADD_JS_PROPERTY(env, object, value, hash), object);
NAPI_CALL_BASE(env, SetNamedProperty(env, object, "version", value.version), object);
NAPI_CALL_BASE(env, SetNamedProperty(env, object, "name", value.name), object);
NAPI_CALL_BASE(env, SetNamedProperty(env, object, "uri", value.uri), object);
NAPI_CALL_BASE(env, SetNamedProperty(env, object, "createTime", value.createTime), object);
NAPI_CALL_BASE(env, SetNamedProperty(env, object, "modifyTime", value.modifyTime), object);
NAPI_CALL_BASE(env, SetNamedProperty(env, object, "size", value.size), object);
NAPI_CALL_BASE(env, SetNamedProperty(env, object, "hash", value.hash), object);
return object;
}

View File

@ -515,7 +515,7 @@ napi_value InnerDeleteRdbStore(napi_env env, napi_callback_info info, std::share
int errCode = RdbHelper::DeleteRdbStore(context->config.GetPath());
LOG_DEBUG("RdbJsKit::DeleteRdbStore failed %{public}d", errCode);
std::shared_ptr<Error> dbInvalidError = std::make_shared<DbInvalidError>();
RDB_CHECK_RETURN_CALL_RESULT(errCode != E_EMPTY_FILE_NAME, context->SetError(dbInvalidError));
RDB_CHECK_RETURN_CALL_RESULT(errCode != E_INVALID_FILE_PATH, context->SetError(dbInvalidError));
return (errCode == E_OK) ? OK : ERR;
};
auto output = [context](napi_env env, napi_value &result) -> int {

View File

@ -28,6 +28,7 @@ sources = [
"src/entry_point.cpp",
"src/napi_async_call.cpp",
"src/napi_rdb_const_properties.cpp",
"src/napi_rdb_error.cpp",
"src/napi_rdb_js_utils.cpp",
"src/napi_rdb_predicates.cpp",
"src/napi_rdb_store.cpp",

View File

@ -35,12 +35,12 @@ extern bool g_sync;
#define ASYNC &g_async
#define SYNC &g_sync
class Context {
class ContextBase {
public:
void SetAction(napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output);
void SetAll(napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output);
void SetError(std::shared_ptr<Error> error);
virtual ~Context();
virtual ~ContextBase();
napi_env env_ = nullptr;
bool isAsync_ = true;
@ -56,12 +56,12 @@ public:
OutputAction output_ = nullptr;
ExecuteAction exec_ = nullptr;
napi_value result_ = nullptr;
std::shared_ptr<Context> keep_;
std::shared_ptr<ContextBase> keep_;
};
class AsyncCall final {
public:
static napi_value Call(napi_env env, std::shared_ptr<Context> context);
static napi_value Call(napi_env env, std::shared_ptr<ContextBase> context);
private:
enum { ARG_ERROR, ARG_DATA, ARG_BUTT };
@ -70,8 +70,8 @@ private:
static void OnReturn(napi_env env, napi_status status, void *data);
static void OnComplete(napi_env env, napi_status status, void *data);
static void SetBusinessError(napi_env env, std::shared_ptr<Error> error, napi_value *businessError);
static napi_value Async(napi_env env, std::shared_ptr<Context> context);
static napi_value Sync(napi_env env, std::shared_ptr<Context> context);
static napi_value Async(napi_env env, std::shared_ptr<ContextBase> context);
static napi_value Sync(napi_env env, std::shared_ptr<ContextBase> context);
};
} // namespace RelationalStoreJsKit
} // namespace OHOS

View File

@ -26,28 +26,31 @@ constexpr int MAX_INPUT_COUNT = 10;
constexpr int OK = 0;
constexpr int ERR = -1;
constexpr int E_PARAM_ERROR = 401;
constexpr int E_NON_SYSTEM_APP_ERROR = 202;
constexpr int E_PARAM_ERROR = 401;
constexpr int E_NOT_SUPPORTED = 801;
constexpr int E_INNER_ERROR = 14800000;
constexpr int E_RESULT_GOTO_ERROR = 14800012;
constexpr int E_NOT_STAGE_MODE = 14801001;
constexpr int E_DATA_GROUP_ID_INVALID = 14801002;
const static std::map<int, std::string> ERROR_MAPS = {
{ NativeRdb::E_WAL_SIZE_OVER_LIMIT, "The WAL file size over default limit." },
{ NativeRdb::E_EMPTY_FILE_NAME, "Failed to open or delete database by invalid database path." },
{ NativeRdb::E_INVALID_FILE_PATH, "Failed to open database by database corrupted" },
{ NativeRdb::E_NOT_SUPPORTED, "Capability not supported" },
{ E_RESULT_GOTO_ERROR, "The result set is empty or the specified location is invalid." },
{ NativeRdb::E_INVALID_STATEMENT, "The column value is null or the column type is incompatible." },
{ E_NOT_STAGE_MODE, "Only supported in stage mode." },
{ E_DATA_GROUP_ID_INVALID, "The data group id is invalid." },
{ NativeRdb::E_GET_DATAOBSMGRCLIENT_FAIL, "Failed to get DataObsMgrClient." },
{ NativeRdb::E_TYPE_MISMATCH, "The type of the distributed table does not match" },
{ NativeRdb::E_DATABASE_FULL, "database or disk is full." }
struct JsErrorCode {
int32_t status;
int32_t jsCode;
const char *message;
};
const std::optional<JsErrorCode> GetJsErrorCode(int32_t errorCode);
#define ASSERT(condition, message, retVal) \
do { \
if (!(condition)) { \
LOG_ERROR("test (" #condition ") failed: " message); \
return retVal; \
} \
} while (0)
#define RDB_REVT_NOTHING
#define RDB_DO_NOTHING
#define RDB_NAPI_ASSERT_BASE(env, assertion, error, retVal) \
do { \
@ -101,10 +104,11 @@ class InnerError : public Error {
public:
InnerError(int code)
{
auto iter = ERROR_MAPS.find(code);
if (iter != ERROR_MAPS.end()) {
code_ = code;
msg_ = iter->second;
auto errorMsg = GetJsErrorCode(code);
if (errorMsg.has_value()) {
auto napiError = errorMsg.value();
code_ = napiError.jsCode;
msg_ = napiError.message;
} else {
code_ = E_INNER_ERROR;
msg_ = "Inner error. Inner code is " + std::to_string(code % E_INNER_ERROR);
@ -133,19 +137,28 @@ private:
class ParamError : public Error {
public:
ParamError(const std::string &needed, const std::string &mustbe) : needed_(needed), mustbe_(mustbe){};
ParamError(const std::string &needed, const std::string &mustbe)
{
msg_ = "Parameter error. The " + needed + " must be " + mustbe;
};
ParamError(const std::string &errMsg)
{
msg_ = "Parameter error." + errMsg;
}
std::string GetMessage() override
{
return "Parameter error. The " + needed_ + " must be " + mustbe_;
return msg_;
};
int GetCode() override
{
return E_PARAM_ERROR;
};
private:
std::string needed_;
std::string mustbe_;
std::string msg_;
};
class NonSystemError : public Error {

View File

@ -16,13 +16,14 @@
#ifndef RDB_JSKIT_NAPI_RDB_JS_UTILS_H
#define RDB_JSKIT_NAPI_RDB_JS_UTILS_H
#include <stdint.h>
#include "asset_value.h"
#include "js_utils.h"
#include "napi_rdb_error.h"
#include "napi_rdb_store_observer.h"
#include "rdb_store_config.h"
#include "result_set.h"
#include "value_object.h"
#include "rdb_types.h"
namespace OHOS::AppDataMgrJsKit {
namespace JSUtils {
using Asset = OHOS::NativeRdb::AssetValue;
@ -31,6 +32,29 @@ using ValueObject = OHOS::NativeRdb::ValueObject;
using Date = OHOS::DistributedRdb::Date;
using JSChangeInfo = OHOS::RelationalStoreJsKit::NapiRdbStoreObserver::JSChangeInfo;
using PRIKey = OHOS::DistributedRdb::RdbStoreObserver::PrimaryKey;
using Error = RelationalStoreJsKit::Error;
using SecurityLevel = NativeRdb::SecurityLevel;
using RdbStoreConfig = NativeRdb::RdbStoreConfig;
struct RdbConfig {
bool isEncrypt = false;
bool isSearchable = false;
bool isAutoClean = false;
SecurityLevel securityLevel = SecurityLevel::LAST;
std::string dataGroupId;
std::string name;
std::string customDir;
std::string path;
};
struct ContextParam {
std::string bundleName;
std::string moduleName;
std::string baseDir;
int32_t area;
bool isSystemApp = false;
bool isStageMode = true;
};
template<>
int32_t Convert2Value(napi_env env, napi_value input, Asset &output);
@ -44,6 +68,12 @@ int32_t Convert2Value(napi_env env, napi_value jsValue, DistributedRdb::Distribu
template<>
int32_t Convert2Value(napi_env env, napi_value jsValue, ValueObject &valueObject);
template<>
int32_t Convert2Value(napi_env env, napi_value jsValue, RdbConfig &rdbConfig);
template<>
int32_t Convert2Value(napi_env env, napi_value jsValue, ContextParam &context);
template<>
napi_value Convert2JSValue(napi_env env, const Asset &value);
@ -69,6 +99,13 @@ template<>
napi_value Convert2JSValue(napi_env env, const Date &date);
template<>
std::string ToString(const PRIKey &key);
bool IsNapiString(napi_env env, napi_value value);
std::tuple<int32_t, std::shared_ptr<Error>> GetRealPath(
napi_env env, napi_value jsValue, RdbConfig &rdbConfig, ContextParam &param);
RdbStoreConfig GetRdbStoreConfig(const RdbConfig &rdbConfig, const ContextParam &param);
}; // namespace JSUtils
} // namespace OHOS::AppDataMgrJsKit
#endif // RDB_JSKIT_NAPI_RDB_JS_UTILS_H

View File

@ -55,6 +55,7 @@ private:
static napi_value Count(napi_env env, napi_callback_info info);
static napi_value Replace(napi_env env, napi_callback_info info);
static napi_value Attach(napi_env env, napi_callback_info info);
static napi_value Detach(napi_env env, napi_callback_info info);
static napi_value GetPath(napi_env env, napi_callback_info info);
static napi_value IsMemoryRdb(napi_env env, napi_callback_info info);
static napi_value IsHoldingConnection(napi_env env, napi_callback_info info);
@ -80,6 +81,8 @@ private:
static napi_value QuerySharingResource(napi_env env, napi_callback_info info);
static constexpr int EVENT_HANDLE_NUM = 2;
static constexpr int WAIT_TIME_DEFAULT = 2;
static constexpr int WAIT_TIME_LIMIT = 300;
napi_value OnRemote(napi_env env, size_t argc, napi_value *argv);
napi_value OnLocal(napi_env env, const DistributedRdb::SubscribeOption &option, napi_value callback);

View File

@ -52,6 +52,7 @@ private:
static napi_value Count(napi_env env, napi_callback_info info);
static napi_value Replace(napi_env env, napi_callback_info info);
static napi_value Attach(napi_env env, napi_callback_info info);
static napi_value Detach(napi_env env, napi_callback_info info);
static napi_value GetPath(napi_env env, napi_callback_info info);
static napi_value IsMemoryRdb(napi_env env, napi_callback_info info);
static napi_value IsHoldingConnection(napi_env env, napi_callback_info info);

View File

@ -26,7 +26,7 @@ namespace OHOS {
namespace RelationalStoreJsKit {
bool g_async = true; // do not reset the value, used in DECLARE_NAPI_FUNCTION_WITH_DATA only
bool g_sync = false; // do not reset the value, used in DECLARE_NAPI_FUNCTION_WITH_DATA only
void Context::SetAction(
void ContextBase::SetAction(
napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output)
{
env_ = env;
@ -59,7 +59,7 @@ void Context::SetAction(
napi_create_reference(env, self, 1, &self_);
}
void Context::SetAll(
void ContextBase::SetAll(
napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output)
{
env_ = env;
@ -78,12 +78,12 @@ void Context::SetAll(
napi_create_reference(env, self, 1, &self_);
}
void Context::SetError(std::shared_ptr<Error> err)
void ContextBase::SetError(std::shared_ptr<Error> err)
{
error = err;
}
Context::~Context()
ContextBase::~ContextBase()
{
if (env_ == nullptr) {
return;
@ -113,12 +113,12 @@ void AsyncCall::SetBusinessError(napi_env env, std::shared_ptr<Error> error, nap
}
}
napi_value AsyncCall::Call(napi_env env, std::shared_ptr<Context> context)
napi_value AsyncCall::Call(napi_env env, std::shared_ptr<ContextBase> context)
{
return context->isAsync_ ? Async(env, context) : Sync(env, context);
}
napi_value AsyncCall::Async(napi_env env, std::shared_ptr<Context> context)
napi_value AsyncCall::Async(napi_env env, std::shared_ptr<ContextBase> context)
{
napi_value promise = nullptr;
if (context->callback_ == nullptr) {
@ -142,7 +142,7 @@ napi_value AsyncCall::Async(napi_env env, std::shared_ptr<Context> context)
return promise;
}
napi_value AsyncCall::Sync(napi_env env, std::shared_ptr<Context> context)
napi_value AsyncCall::Sync(napi_env env, std::shared_ptr<ContextBase> context)
{
OnExecute(env, reinterpret_cast<void *>(context.get()));
OnComplete(env, reinterpret_cast<void *>(context.get()));
@ -152,7 +152,7 @@ napi_value AsyncCall::Sync(napi_env env, std::shared_ptr<Context> context)
void AsyncCall::OnExecute(napi_env env, void *data)
{
DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
Context *context = reinterpret_cast<Context *>(data);
ContextBase *context = reinterpret_cast<ContextBase *>(data);
if (context->error == nullptr && context->exec_) {
context->execCode_ = context->exec_();
}
@ -161,7 +161,7 @@ void AsyncCall::OnExecute(napi_env env, void *data)
void AsyncCall::OnComplete(napi_env env, void *data)
{
Context *context = reinterpret_cast<Context *>(data);
ContextBase *context = reinterpret_cast<ContextBase *>(data);
if (context->execCode_ != NativeRdb::E_OK) {
context->SetError(std::make_shared<InnerError>(context->execCode_));
}
@ -181,7 +181,7 @@ void AsyncCall::OnComplete(napi_env env, napi_status status, void *data)
void AsyncCall::OnReturn(napi_env env, napi_status status, void *data)
{
Context *context = reinterpret_cast<Context *>(data);
ContextBase *context = reinterpret_cast<ContextBase *>(data);
napi_value result[ARG_BUTT] = { 0 };
// if out function status is ok then async renturn output data, else return error.
if (context->error == nullptr) {

View File

@ -0,0 +1,53 @@
/*
* 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 "napi_rdb_error.h"
namespace OHOS {
namespace RelationalStoreJsKit {
using JsErrorCode = OHOS::RelationalStoreJsKit::JsErrorCode;
static constexpr JsErrorCode JS_ERROR_CODE_MSGS[] = {
{ NativeRdb::E_NOT_SUPPORTED, 801, "Capability not supported." },
{ NativeRdb::E_DATA_BASE_CORRUPTED, 14800011, "Database corrupted." },
{ NativeRdb::E_INVALID_FILE_PATH, 14800010, "Invalid database path." },
{ E_RESULT_GOTO_ERROR, 14800012, "The result set is empty or the specified location is invalid." },
{ NativeRdb::E_INVALID_STATEMENT, 14800013, "The column value is null or the column type is incompatible." },
{ NativeRdb::E_DATABASE_BUSY, 14800015, "The database does not respond." },
{ NativeRdb::E_WAL_SIZE_OVER_LIMIT, 14800047, "The WAL file size over default limit." },
{ NativeRdb::E_GET_DATAOBSMGRCLIENT_FAIL, 14801050, "Failed to get DataObsMgrClient." },
{ NativeRdb::E_TYPE_MISMATCH, 14800051, "The type of the distributed table does not match." },
{ NativeRdb::E_DATABASE_FULL, 14800052, "database or disk is full."},
{ NativeRdb::E_ATTACHED_DATABASE_EXIST, 14800016, "The database is already attached."},
{ E_NOT_STAGE_MODE, 14801001, "Only supported in stage mode." },
{ E_DATA_GROUP_ID_INVALID, 14801002, "The data group id is invalid." }
};
const std::optional<JsErrorCode> GetJsErrorCode(int32_t errorCode)
{
auto jsErrorCode = JsErrorCode{ errorCode, -1, "" };
auto iter = std::lower_bound(JS_ERROR_CODE_MSGS,
JS_ERROR_CODE_MSGS + sizeof(JS_ERROR_CODE_MSGS) / sizeof(JS_ERROR_CODE_MSGS[0]), jsErrorCode,
[](const JsErrorCode &jsErrorCode1, const JsErrorCode &jsErrorCode2) {
return jsErrorCode1.status < jsErrorCode2.status;
});
if (iter < JS_ERROR_CODE_MSGS + sizeof(JS_ERROR_CODE_MSGS) / sizeof(JS_ERROR_CODE_MSGS[0]) &&
iter->status == errorCode) {
return *iter;
}
return std::nullopt;
}
} // namespace RelationalStoreJsKit
} // namespace OHOS

View File

@ -15,21 +15,32 @@
#include "napi_rdb_js_utils.h"
#include <memory>
#include <tuple>
#include "js_ability.h"
#include "js_native_api_types.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_sql_utils.h"
#include "result_set.h"
#define NAPI_CALL_RETURN_ERR(theCall, retVal) \
do { \
if ((theCall) != napi_ok) { \
return retVal; \
} \
do { \
if ((theCall) != napi_ok) { \
return retVal; \
} \
} while (0)
#ifndef PATH_SPLIT
#define PATH_SPLIT '/'
#endif
namespace OHOS::AppDataMgrJsKit {
namespace JSUtils {
using namespace OHOS::Rdb;
using namespace NativeRdb;
using RelationalStoreJsKit::ParamError;
using namespace RelationalStoreJsKit;
template<>
int32_t Convert2Value(napi_env env, napi_value jsValue, Asset &output)
{
@ -42,20 +53,17 @@ int32_t Convert2Value(napi_env env, napi_value jsValue, Asset &output)
return napi_invalid_arg;
}
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, name), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, uri), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, createTime), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, modifyTime), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, size), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, jsValue, output, path), napi_invalid_arg);
output.hash = output.modifyTime + "_" + output.size;
auto jsStatus = GetNamedProperty(env, jsValue, "status");
if (jsStatus != nullptr) {
Convert2ValueExt(env, jsStatus, output.status);
}
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "name", output.name), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "uri", output.uri), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "createTime", output.createTime), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "modifyTime", output.modifyTime), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "size", output.size), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "path", output.path), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, jsValue, "status", output.status, true), napi_invalid_arg);
if (output.status != AssetValue::STATUS_DELETE) {
output.status = AssetValue::STATUS_UNKNOWN;
}
output.hash = output.modifyTime + "_" + output.size;
return napi_ok;
}
@ -69,9 +77,9 @@ int32_t Convert2Value(napi_env env, napi_value input, DistributedRdb::Reference
return napi_invalid_arg;
}
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, input, output, sourceTable), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, input, output, targetTable), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, input, output, refFields), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "sourceTable", output.sourceTable), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "targetTable", output.targetTable), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "refFields", output.refFields), napi_invalid_arg);
return napi_ok;
}
@ -85,12 +93,8 @@ int32_t Convert2Value(napi_env env, napi_value input, DistributedRdb::Distribute
return napi_invalid_arg;
}
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, input, output, autoSync), napi_invalid_arg);
bool exist = false;
status = napi_has_named_property(env, input, "references", &exist);
if (status == napi_ok && exist) {
NAPI_CALL_RETURN_ERR(GET_PROPERTY(env, input, output, references), napi_invalid_arg);
}
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "autoSync", output.autoSync), napi_invalid_arg);
NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "references", output.references, true), napi_invalid_arg);
return napi_ok;
}
@ -109,28 +113,27 @@ napi_value Convert2JSValue(napi_env env, const Asset &value)
{
napi_value object = nullptr;
NAPI_CALL_RETURN_ERR(napi_create_object(env, &object), object);
NAPI_CALL_RETURN_ERR(ADD_JS_PROPERTY(env, object, value, name), object);
NAPI_CALL_RETURN_ERR(ADD_JS_PROPERTY(env, object, value, uri), object);
NAPI_CALL_RETURN_ERR(ADD_JS_PROPERTY(env, object, value, createTime), object);
NAPI_CALL_RETURN_ERR(ADD_JS_PROPERTY(env, object, value, modifyTime), object);
NAPI_CALL_RETURN_ERR(ADD_JS_PROPERTY(env, object, value, size), object);
NAPI_CALL_RETURN_ERR(ADD_JS_PROPERTY(env, object, value, path), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "name", value.name), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "uri", value.uri), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "createTime", value.createTime), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "modifyTime", value.modifyTime), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "size", value.size), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "path", value.path), object);
auto outputStatus = value.status & ~0xF0000000;
NAPI_CALL_RETURN_ERR(napi_set_named_property(env, object, "status", Convert2JSValue(env, outputStatus)), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "status", outputStatus), object);
return object;
}
template<>
napi_value Convert2JSValue(napi_env env, const RowEntity &rowEntity)
{
napi_value ret = nullptr;
NAPI_CALL(env, napi_create_object(env, &ret));
napi_value object = nullptr;
NAPI_CALL_RETURN_ERR(napi_create_object(env, &object), object);
auto &values = rowEntity.Get();
for (auto const &[key, object] : values) {
napi_value value = JSUtils::Convert2JSValue(env, object);
NAPI_CALL(env, napi_set_named_property(env, ret, key.c_str(), value));
for (auto const &[key, value] : values) {
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, key.c_str(), value), object);
}
return ret;
return object;
}
template<>
@ -142,37 +145,25 @@ napi_value Convert2JSValue(napi_env env, const ValueObject &valueObject)
template<>
napi_value Convert2JSValue(napi_env env, const DistributedRdb::Statistic &statistic)
{
napi_value jsValue = nullptr;
napi_status status = napi_create_object(env, &jsValue);
if (status != napi_ok) {
return nullptr;
}
napi_value total = Convert2JSValue(env, statistic.total);
napi_value success = Convert2JSValue(env, statistic.success);
napi_value failed = Convert2JSValue(env, statistic.failed);
napi_value untreated = Convert2JSValue(env, statistic.untreated);
napi_value object = nullptr;
NAPI_CALL_RETURN_ERR(napi_create_object(env, &object), object);
napi_set_named_property(env, jsValue, "total", total);
napi_set_named_property(env, jsValue, "success", success);
napi_set_named_property(env, jsValue, "successful", success);
napi_set_named_property(env, jsValue, "failed", failed);
napi_set_named_property(env, jsValue, "remained", untreated);
return jsValue;
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "total", statistic.total), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "success", statistic.success), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "successful", statistic.success), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "failed", statistic.failed), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "remained", statistic.untreated), object);
return object;
}
template<>
napi_value Convert2JSValue(napi_env env, const DistributedRdb::TableDetail &tableDetail)
{
napi_value jsValue = nullptr;
napi_status status = napi_create_object(env, &jsValue);
if (status != napi_ok) {
return nullptr;
}
napi_value upload = Convert2JSValue(env, tableDetail.upload);
napi_value download = Convert2JSValue(env, tableDetail.download);
napi_set_named_property(env, jsValue, "upload", upload);
napi_set_named_property(env, jsValue, "download", download);
return jsValue;
napi_value object = nullptr;
NAPI_CALL_RETURN_ERR(napi_create_object(env, &object), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "upload", tableDetail.upload), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "download", tableDetail.download), object);
return object;
}
template<>
@ -202,21 +193,19 @@ napi_value Convert2JSValue(napi_env env, const DistributedRdb::TableDetails &tab
template<>
napi_value Convert2JSValue(napi_env env, const DistributedRdb::ProgressDetail &progressDetail)
{
napi_value jsValue = nullptr;
napi_status status = napi_create_object(env, &jsValue);
if (status != napi_ok) {
return nullptr;
}
napi_value object = nullptr;
NAPI_CALL_RETURN_ERR(napi_create_object(env, &object), object);
napi_value schedule = Convert2JSValue(env, progressDetail.progress);
napi_value code = Convert2JSValue(env, progressDetail.code);
napi_value details = Convert2JSValue(env, progressDetail.details);
if (details == nullptr) {
return nullptr;
}
napi_set_named_property(env, jsValue, "schedule", schedule);
napi_set_named_property(env, jsValue, "code", code);
napi_set_named_property(env, jsValue, "details", details);
return jsValue;
napi_set_named_property(env, object, "schedule", schedule);
napi_set_named_property(env, object, "code", code);
napi_set_named_property(env, object, "details", details);
return object;
}
template<>
@ -229,27 +218,21 @@ template<>
napi_value Convert2JSValue(napi_env env, const JSChangeInfo &value)
{
napi_value object = nullptr;
auto status = napi_create_object(env, &object);
if (status != napi_ok) {
return nullptr;
}
ADD_JS_PROPERTY(env, object, value, table);
ADD_JS_PROPERTY(env, object, value, type);
ADD_JS_PROPERTY(env, object, value, inserted);
ADD_JS_PROPERTY(env, object, value, updated);
ADD_JS_PROPERTY(env, object, value, deleted);
NAPI_CALL_RETURN_ERR(napi_create_object(env, &object), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "table", value.table), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "type", value.type), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "inserted", value.inserted), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "updated", value.updated), object);
NAPI_CALL_RETURN_ERR(SetNamedProperty(env, object, "deleted", value.deleted), object);
return object;
}
template<>
napi_value Convert2JSValue(napi_env env, const Date &date)
{
napi_value jsValue = nullptr;
napi_status status = napi_create_date(env, date, &jsValue);
if (status != napi_ok) {
return nullptr;
}
return jsValue;
napi_value jsDeta = nullptr;
NAPI_CALL_RETURN_ERR(napi_create_date(env, date, &jsDeta), jsDeta);
return jsDeta;
}
template<>
@ -269,5 +252,173 @@ std::string ToString(const PRIKey &key)
}
return {};
}
bool IsNapiString(napi_env env, napi_value value)
{
napi_valuetype type = napi_undefined;
NAPI_CALL_BASE(env, napi_typeof(env, value, &type), false);
return type == napi_string;
}
int32_t GetLevel(SecurityLevel level, SecurityLevel &out)
{
switch (level) {
case SecurityLevel::S1:
case SecurityLevel::S2:
case SecurityLevel::S3:
case SecurityLevel::S4:
out = level;
return napi_ok;
default:
return napi_invalid_arg;
}
}
template<>
int32_t Convert2Value(napi_env env, napi_value jsValue, RdbConfig &rdbConfig)
{
int32_t status = GetNamedProperty(env, jsValue, "encrypt", rdbConfig.isEncrypt, true);
ASSERT(OK == status, "get encrypt failed.", napi_invalid_arg);
int32_t securityLevel;
status = GetNamedProperty(env, jsValue, "securityLevel", securityLevel);
ASSERT(OK == status, "get securityLevel failed.", napi_invalid_arg);
status = GetLevel(static_cast<SecurityLevel>(securityLevel), rdbConfig.securityLevel);
ASSERT(status == napi_ok, "get securityLevel failed", status);
status = GetNamedProperty(env, jsValue, "dataGroupId", rdbConfig.dataGroupId, true);
ASSERT(OK == status, "get dataGroupId failed.", napi_invalid_arg);
status = GetNamedProperty(env, jsValue, "autoCleanDirtyData", rdbConfig.isAutoClean, true);
ASSERT(OK == status, "get autoCleanDirtyData failed.", napi_invalid_arg);
status = GetNamedProperty(env, jsValue, "name", rdbConfig.name);
ASSERT(OK == status, "get name failed.", napi_invalid_arg);
status = GetNamedProperty(env, jsValue, "customDir", rdbConfig.customDir, true);
ASSERT(OK == status, "get customDir failed.", napi_invalid_arg);
GetNamedProperty(env, jsValue, "isSearchable", rdbConfig.isSearchable, true);
ASSERT(OK == status, "get isSearchable failed.", napi_invalid_arg);
return napi_ok;
}
int32_t GetCurrentAbilityParam(napi_env env, napi_value jsValue, ContextParam &param)
{
auto ability = AbilityRuntime::GetCurrentAbility(env);
if (ability == nullptr) {
LOG_ERROR("GetCurrentAbility failed.");
return napi_invalid_arg;
}
auto abilityContext = ability->GetAbilityContext();
if (abilityContext == nullptr) {
LOG_ERROR("GetAbilityContext failed.");
return napi_invalid_arg;
}
std::shared_ptr<Context> context = std::make_shared<Context>(abilityContext);
param.baseDir = context->GetDatabaseDir();
param.moduleName = context->GetModuleName();
param.area = context->GetArea();
param.bundleName = context->GetBundleName();
param.isSystemApp = context->IsSystemAppCalled();
return napi_ok;
}
template<>
int32_t Convert2Value(napi_env env, napi_value jsValue, ContextParam &param)
{
if (jsValue == nullptr) {
LOG_INFO("hasProp is false -> fa stage");
param.isStageMode = false;
return GetCurrentAbilityParam(env, jsValue, param);
}
int32_t status = GetNamedProperty(env, jsValue, "stageMode", param.isStageMode);
ASSERT(status == napi_ok, "get stageMode param failed", napi_invalid_arg);
if (!param.isStageMode) {
LOG_WARN("isStageMode is false -> fa stage");
return GetCurrentAbilityParam(env, jsValue, param);
}
LOG_DEBUG("stage mode branch");
status = GetNamedProperty(env, jsValue, "databaseDir", param.baseDir);
ASSERT(status == napi_ok, "get databaseDir failed.", napi_invalid_arg);
status = GetNamedProperty(env, jsValue, "area", param.area);
ASSERT(status == napi_ok, "get area failed.", napi_invalid_arg);
napi_value hapInfo = nullptr;
GetNamedProperty(env, jsValue, "currentHapModuleInfo", hapInfo);
if (hapInfo != nullptr) {
status = GetNamedProperty(env, hapInfo, "name", param.moduleName);
ASSERT(status == napi_ok, "get currentHapModuleInfo.name failed.", napi_invalid_arg);
}
napi_value appInfo = nullptr;
GetNamedProperty(env, jsValue, "applicationInfo", appInfo);
if (appInfo != nullptr) {
status = GetNamedProperty(env, appInfo, "name", param.bundleName);
ASSERT(status == napi_ok, "get applicationInfo.name failed.", napi_invalid_arg);
status = GetNamedProperty(env, appInfo, "systemApp", param.isSystemApp);
ASSERT(status == napi_ok, "get applicationInfo.systemApp failed.", napi_invalid_arg);
}
return napi_ok;
}
std::tuple<int32_t, std::shared_ptr<Error>> GetRealPath(
napi_env env, napi_value jsValue, RdbConfig &rdbConfig, ContextParam &param)
{
CHECK_RETURN_CORE(rdbConfig.name.find(PATH_SPLIT) == std::string::npos, RDB_DO_NOTHING,
std::make_tuple(ERR, std::make_shared<ParamError>("StoreConfig.name", "a file name without path.")));
if (!rdbConfig.customDir.empty()) {
// determine if the first character of customDir is '/'
CHECK_RETURN_CORE(rdbConfig.customDir.find_first_of(PATH_SPLIT) != 0, RDB_DO_NOTHING,
std::make_tuple(ERR, std::make_shared<ParamError>("customDir", "a relative directory.")));
// customDir length is limited to 128 bytes
CHECK_RETURN_CORE(rdbConfig.customDir.length() <= 128, RDB_DO_NOTHING,
std::make_tuple(ERR, std::make_shared<ParamError>("customDir length", "less than or equal to 128 bytes.")));
}
std::string baseDir = param.baseDir;
if (!rdbConfig.dataGroupId.empty()) {
if (!param.isStageMode) {
return std::make_tuple(ERR, std::make_shared<InnerError>(E_NOT_STAGE_MODE));
}
auto stageContext = AbilityRuntime::GetStageModeContext(env, jsValue);
if (stageContext == nullptr) {
return std::make_tuple(ERR, std::make_shared<ParamError>("Illegal context."));
}
std::string groupDir;
int errCode = stageContext->GetSystemDatabaseDir(rdbConfig.dataGroupId, false, groupDir);
CHECK_RETURN_CORE(errCode == E_OK || !groupDir.empty(), RDB_DO_NOTHING,
std::make_tuple(ERR, std::make_shared<InnerError>(E_DATA_GROUP_ID_INVALID)));
baseDir = groupDir;
}
auto [realPath, errorCode] = RdbSqlUtils::GetDefaultDatabasePath(baseDir, rdbConfig.name, rdbConfig.customDir);
// realPath length is limited to 1024 bytes
CHECK_RETURN_CORE(errorCode == E_OK && realPath.length() <= 1024, RDB_DO_NOTHING,
std::make_tuple(ERR, std::make_shared<ParamError>("database path", "a valid path.")));
rdbConfig.path = realPath;
return std::make_tuple(E_OK, nullptr);
}
RdbStoreConfig GetRdbStoreConfig(const RdbConfig &rdbConfig, const ContextParam &param)
{
RdbStoreConfig rdbStoreConfig(rdbConfig.path);
rdbStoreConfig.SetEncryptStatus(rdbConfig.isEncrypt);
rdbStoreConfig.SetSearchable(rdbConfig.isSearchable);
rdbStoreConfig.SetAutoClean(rdbConfig.isAutoClean);
rdbStoreConfig.SetSecurityLevel(rdbConfig.securityLevel);
rdbStoreConfig.SetDataGroupId(rdbConfig.dataGroupId);
rdbStoreConfig.SetName(rdbConfig.name);
rdbStoreConfig.SetCustomDir(rdbConfig.customDir);
if (!param.bundleName.empty()) {
rdbStoreConfig.SetBundleName(param.bundleName);
}
rdbStoreConfig.SetModuleName(param.moduleName);
rdbStoreConfig.SetArea(param.area);
return rdbStoreConfig;
}
}; // namespace JSUtils
} // namespace OHOS::AppDataMgrJsKit

View File

@ -20,7 +20,9 @@
#include <vector>
#include <algorithm>
#include "js_native_api_types.h"
#include "js_utils.h"
#include "napi_rdb_js_utils.h"
#include "logger.h"
#include "napi_async_call.h"
#include "napi_rdb_error.h"
@ -38,6 +40,7 @@ using namespace OHOS::DataShare;
using namespace OHOS::Rdb;
using namespace OHOS::NativeRdb;
using namespace OHOS::AppDataMgrJsKit;
using namespace OHOS::AppDataMgrJsKit::JSUtils;
#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
using OHOS::DistributedRdb::SubscribeMode;
@ -56,7 +59,7 @@ struct PredicatesProxy {
std::shared_ptr<DataShareAbsPredicates> predicates_;
};
#endif
struct RdbStoreContext : public Context {
struct RdbStoreContext : public ContextBase {
std::string device;
std::string tableName;
std::vector<std::string> tablesNames;
@ -176,6 +179,8 @@ void RdbStoreProxy::Init(napi_env env, napi_value exports)
DECLARE_NAPI_FUNCTION("commit", Commit),
DECLARE_NAPI_FUNCTION("restore", Restore),
DECLARE_NAPI_GETTER_SETTER("version", GetVersion, SetVersion),
DECLARE_NAPI_FUNCTION("attach", Attach),
DECLARE_NAPI_FUNCTION("detach", Detach),
#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
DECLARE_NAPI_FUNCTION("remoteQuery", RemoteQuery),
DECLARE_NAPI_FUNCTION("setDistributedTables", SetDistributedTables),
@ -260,7 +265,7 @@ RdbStoreProxy *GetNativeInstance(napi_env env, napi_value self)
return proxy;
}
int ParserThis(const napi_env &env, const napi_value &self, std::shared_ptr<RdbStoreContext> context)
int ParserThis(const napi_env &env, const napi_value &self, std::shared_ptr<ContextBase> context)
{
RdbStoreProxy *obj = GetNativeInstance(env, self);
CHECK_RETURN_SET(obj && obj->rdbStore_, std::make_shared<ParamError>("RdbStore", "nullptr."));
@ -882,23 +887,101 @@ napi_value RdbStoreProxy::Backup(napi_env env, napi_callback_info info)
return AsyncCall::Call(env, context);
}
struct AttachContext : public ContextBase {
ContextParam param;
RdbConfig config;
std::string attachName;
int32_t waitTime;
int32_t attachedNum;
};
napi_value RdbStoreProxy::Attach(napi_env env, napi_callback_info info)
{
auto context = std::make_shared<RdbStoreContext>();
auto context = std::make_shared<AttachContext>();
auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
CHECK_RETURN_SET_E(argc == 3, std::make_shared<ParamNumError>("3 or 4"));
CHECK_RETURN(OK == ParserThis(env, self, context));
CHECK_RETURN(OK == ParseAlias(env, argv[0], context));
CHECK_RETURN(OK == ParsePath(env, argv[1], context));
int32_t errCode;
// The parameter must be between 2 and 4
CHECK_RETURN_SET_E(argc >= 2 && argc <= 4, std::make_shared<ParamNumError>("2 or 3 or 4"));
// argv[0] may be a string or context.
bool isString = IsNapiString(env, argv[0]);
if (isString) {
errCode = Convert2Value(env, argv[0], context->config.path);
CHECK_RETURN_SET_E(napi_ok == errCode && !context->config.path.empty(),
std::make_shared<ParamError>("fullPath cannot be empty."));
} else {
errCode = Convert2Value(env, argv[0], context->param);
CHECK_RETURN_SET_E(OK == errCode, std::make_shared<ParamError>("Illegal context."));
int errCode = Convert2Value(env, argv[1], context->config);
CHECK_RETURN_SET_E(OK == errCode, std::make_shared<ParamError>("Illegal StoreConfig or name."));
auto [code, err] = GetRealPath(env, argv[0], context->config, context->param);
CHECK_RETURN_SET_E(OK == code, err);
}
// when the first parameter is string, the pos of attachName is 1; otherwise, it is 2
size_t pos = isString ? 1 : 2;
errCode = Convert2Value(env, argv[pos++], context->attachName);
CHECK_RETURN_SET_E(napi_ok == errCode && !context->attachName.empty(),
std::make_shared<ParamError>("attachName cannot be empty."));
context->waitTime = WAIT_TIME_DEFAULT;
if (pos < argc) {
errCode = Convert2ValueExt(env, argv[pos], context->waitTime);
CHECK_RETURN_SET_E(napi_ok == errCode && context->waitTime >= 1 && context->waitTime <= WAIT_TIME_LIMIT,
std::make_shared<ParamError>("waitTime cannot exceed 300s."));
}
};
auto exec = [context]() -> int {
RdbStoreProxy *obj = reinterpret_cast<RdbStoreProxy *>(context->boundObj);
CHECK_RETURN_ERR(obj != nullptr && obj->rdbStore_ != nullptr);
return obj->rdbStore_->Attach(context->aliasName, context->pathName, context->newKey);
auto res = obj->rdbStore_->Attach(
GetRdbStoreConfig(context->config, context->param), context->attachName, context->waitTime);
context->attachedNum = res.second;
return res.first;
};
auto output = [context](napi_env env, napi_value &result) {
napi_status status = napi_get_undefined(env, &result);
CHECK_RETURN_SET_E(status == napi_ok, std::make_shared<InnerError>(E_ERROR));
result = Convert2JSValue(env, context->attachedNum);
CHECK_RETURN_SET_E(result != nullptr, std::make_shared<InnerError>(E_ERROR));
};
context->SetAction(env, info, input, exec, output);
CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
return AsyncCall::Call(env, context);
}
napi_value RdbStoreProxy::Detach(napi_env env, napi_callback_info info)
{
struct DetachContext : public ContextBase {
std::string attachName;
int32_t waitTime;
int32_t attachedNum;
};
auto context = std::make_shared<DetachContext>();
auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
// this interface has 1 or 2 parameters
CHECK_RETURN_SET_E(argc == 1 || argc == 2, std::make_shared<ParamNumError>("1 or 2"));
CHECK_RETURN(OK == ParserThis(env, self, context));
int32_t errCode = Convert2Value(env, argv[0], context->attachName);
CHECK_RETURN_SET_E(napi_ok == errCode && !context->attachName.empty(),
std::make_shared<ParamError>("attachName cannot be empty."));
context->waitTime = WAIT_TIME_DEFAULT;
// parse waitTime when the number of parameters is 2
if (argc == 2) {
errCode = Convert2ValueExt(env, argv[1], context->waitTime);
CHECK_RETURN_SET_E(napi_ok == errCode && context->waitTime < WAIT_TIME_LIMIT,
std::make_shared<ParamError>("waitTime cannot exceed 300s."));
}
};
auto exec = [context]() -> int {
RdbStoreProxy *obj = reinterpret_cast<RdbStoreProxy *>(context->boundObj);
CHECK_RETURN_ERR(obj != nullptr && obj->rdbStore_ != nullptr);
auto res = obj->rdbStore_->Detach(context->attachName, context->waitTime);
context->attachedNum = res.second;
return res.first;
};
auto output = [context](napi_env env, napi_value &result) {
result = Convert2JSValue(env, context->attachedNum);
CHECK_RETURN_SET_E(result != nullptr, std::make_shared<InnerError>(E_ERROR));
};
context->SetAction(env, info, input, exec, output);

View File

@ -16,245 +16,28 @@
#include "napi_rdb_store_helper.h"
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include "js_ability.h"
#include "js_utils.h"
#include "logger.h"
#include "napi_async_call.h"
#include "napi_rdb_error.h"
#include "napi_rdb_js_utils.h"
#include "napi_rdb_store.h"
#include "napi_rdb_trace.h"
#include "rdb_errno.h"
#include "rdb_open_callback.h"
#include "rdb_sql_utils.h"
#include "rdb_store_config.h"
#include "unistd.h"
using namespace OHOS::Rdb;
using namespace OHOS::NativeRdb;
using namespace OHOS::AppDataMgrJsKit;
using namespace OHOS::AppDataMgrJsKit::JSUtils;
namespace OHOS {
namespace RelationalStoreJsKit {
struct HelperRdbContext : public Context {
RdbStoreConfig config;
std::shared_ptr<RdbStore> proxy;
std::shared_ptr<OHOS::AppDataMgrJsKit::Context> abilitycontext;
bool isSystemAppCalled;
HelperRdbContext() : config(""), proxy(nullptr), isSystemAppCalled(false)
{
}
virtual ~HelperRdbContext(){};
};
int ParseContext(const napi_env &env, const napi_value &object, std::shared_ptr<HelperRdbContext> context)
{
napi_valuetype type = napi_undefined;
napi_typeof(env, object, &type);
CHECK_RETURN_SET(type == napi_object, std::make_shared<ParamError>("context", "object."));
auto abilityContext = JSAbility::GetContext(env, object);
CHECK_RETURN_SET(abilityContext != nullptr, std::make_shared<ParamError>("context", "a Context."));
context->abilitycontext = abilityContext;
return OK;
}
int ParseIsEncrypt(const napi_env &env, const napi_value &object, std::shared_ptr<HelperRdbContext> context)
{
napi_value value = nullptr;
napi_status status = napi_get_named_property(env, object, "encrypt", &value);
if (status == napi_ok && value != nullptr) {
bool isEncrypt = false;
JSUtils::Convert2Value(env, value, isEncrypt);
context->config.SetEncryptStatus(isEncrypt);
}
return OK;
}
int ParseIsSearchable(const napi_env &env, const napi_value &object, std::shared_ptr<HelperRdbContext> context)
{
napi_value value = nullptr;
napi_status status = napi_get_named_property(env, object, "isSearchable", &value);
if (status == napi_ok && value != nullptr) {
bool isSearchable = false;
auto status = JSUtils::Convert2Value(env, value, isSearchable);
if (status != napi_ok) {
return napi_invalid_arg;
}
context->config.SetSearchable(isSearchable);
}
return OK;
}
int ParseContextProperty(const napi_env &env, std::shared_ptr<HelperRdbContext> context)
{
context->config.SetModuleName(context->abilitycontext->GetModuleName());
context->config.SetArea(context->abilitycontext->GetArea());
context->config.SetBundleName(context->abilitycontext->GetBundleName());
if (!context->abilitycontext->IsHasProxyDataConfig()) {
context->config.SetUri(context->abilitycontext->GetUri());
context->config.SetReadPermission(context->abilitycontext->GetReadPermission());
context->config.SetWritePermission(context->abilitycontext->GetWritePermission());
} else {
context->config.SetUri("dataProxy");
}
context->isSystemAppCalled = context->abilitycontext->IsSystemAppCalled();
return OK;
}
int ParseDatabaseName(const napi_env &env, const napi_value &object, std::shared_ptr<HelperRdbContext> context)
{
napi_value value = nullptr;
napi_get_named_property(env, object, "name", &value);
CHECK_RETURN_SET(value != nullptr, std::make_shared<ParamError>("config", "a StoreConfig."));
std::string databaseName = JSUtils::Convert2String(env, value);
CHECK_RETURN_SET(!databaseName.empty(), std::make_shared<ParamError>("StoreConfig.name", "not empty."));
if (databaseName.find("/") != std::string::npos) {
CHECK_RETURN_SET(false, std::make_shared<ParamError>("StoreConfig.name", "a file name without path"));
}
context->config.SetName(databaseName);
return OK;
}
int ParseDatabasePath(const napi_env &env, const napi_value &object, std::shared_ptr<HelperRdbContext> context)
{
int errorCode = E_OK;
std::string defaultDir;
if (context->config.GetDataGroupId().empty()) {
defaultDir = context->abilitycontext->GetDatabaseDir();
} else {
errorCode = context->abilitycontext->GetSystemDatabaseDir(context->config.GetDataGroupId(), defaultDir);
CHECK_RETURN_SET((errorCode == E_OK), std::make_shared<InnerError>(E_DATA_GROUP_ID_INVALID));
}
bool hasProp = false;
std::string customDir;
napi_status status = napi_has_named_property(env, object, "customDir", &hasProp);
if (status == napi_ok && hasProp) {
napi_value value = nullptr;
napi_get_named_property(env, object, "customDir", &value);
CHECK_RETURN_SET(value != nullptr, std::make_shared<ParamError>("customDir", "a valid value."));
JSUtils::Convert2Value(env, value, customDir);
size_t pos = customDir.find_first_of('/');
// determine if the first character of customDir is '/'
CHECK_RETURN_SET(pos != 0, std::make_shared<ParamError>("customDir", "a relative directory."));
// customDir length is limited to 128 bytes
CHECK_RETURN_SET(customDir.length() <= 128,
std::make_shared<ParamError>("customDir length", "less than or equal to 128 bytes."));
context->config.SetCustomDir(customDir);
}
auto [realPath, errCode] = RdbSqlUtils::GetDefaultDatabasePath(defaultDir, context->config.GetName(), customDir);
// realPath length is limited to 1024 bytes
CHECK_RETURN_SET(errCode == E_OK && realPath.length() <= 1024,
std::make_shared<ParamError>("database path", "a valid path."));
context->config.SetPath(std::move(realPath));
return OK;
}
int ParseSecurityLevel(const napi_env &env, const napi_value &object, std::shared_ptr<HelperRdbContext> context)
{
napi_value value = nullptr;
bool hasProp = false;
napi_status status = napi_has_named_property(env, object, "securityLevel", &hasProp);
CHECK_RETURN_SET(status == napi_ok && hasProp, std::make_shared<ParamError>("config", "with securityLevel."));
status = napi_get_named_property(env, object, "securityLevel", &value);
CHECK_RETURN_SET(status == napi_ok, std::make_shared<ParamError>("config", "with securityLevel."));
int32_t securityLevel;
napi_get_value_int32(env, value, &securityLevel);
SecurityLevel sl = static_cast<SecurityLevel>(securityLevel);
LOG_DEBUG("Get sl:%{public}d", securityLevel);
bool isValidSecurityLevel = sl >= SecurityLevel::S1 && sl < SecurityLevel::LAST;
CHECK_RETURN_SET(isValidSecurityLevel, std::make_shared<ParamError>("config", "with correct securityLevel."));
context->config.SetSecurityLevel(sl);
LOG_DEBUG("ParseSecurityLevel end");
return OK;
}
int ParseDataGroupId(const napi_env &env, const napi_value &object, std::shared_ptr<HelperRdbContext> context)
{
bool hasProp = false;
napi_status status = napi_has_named_property(env, object, "dataGroupId", &hasProp);
if (status == napi_ok && hasProp) {
napi_value value = nullptr;
status = napi_get_named_property(env, object, "dataGroupId", &value);
CHECK_RETURN_SET(status == napi_ok, std::make_shared<ParamError>("config", "with dataGroupId."));
std::string dataGroupId = JSUtils::Convert2String(env, value);
CHECK_RETURN_SET(!dataGroupId.empty(), std::make_shared<ParamError>
("StoreConfig.dataGroupId", "not empty."));
CHECK_RETURN_SET(context->abilitycontext->IsStageMode(), std::make_shared<InnerError>(E_NOT_STAGE_MODE));
context->config.SetDataGroupId(JSUtils::Convert2String(env, value));
}
return OK;
}
int ParseAutoCleanDirtyData(const napi_env &env, const napi_value &object, std::shared_ptr<HelperRdbContext> context)
{
bool hasProp = false;
napi_status status = napi_has_named_property(env, object, "autoCleanDirtyData", &hasProp);
if (status == napi_ok && hasProp) {
napi_value value = nullptr;
status = napi_get_named_property(env, object, "autoCleanDirtyData", &value);
CHECK_RETURN_SET(status == napi_ok, std::make_shared<ParamError>("config", "with autoCleanDirtyData."));
bool isAutoClean = true;
JSUtils::Convert2Value(env, value, isAutoClean);
context->config.SetAutoClean(isAutoClean);
}
return OK;
}
int ParseStoreConfig(const napi_env &env, const napi_value &object, std::shared_ptr<HelperRdbContext> context)
{
CHECK_RETURN_CORE(OK == ParseIsEncrypt(env, object, context), RDB_REVT_NOTHING, ERR);
CHECK_RETURN_CORE(OK == ParseSecurityLevel(env, object, context), RDB_REVT_NOTHING, ERR);
CHECK_RETURN_CORE(OK == ParseDataGroupId(env, object, context), RDB_REVT_NOTHING, ERR);
CHECK_RETURN_CORE(OK == ParseAutoCleanDirtyData(env, object, context), RDB_REVT_NOTHING, ERR);
CHECK_RETURN_CORE(OK == ParseContextProperty(env, context), RDB_REVT_NOTHING, ERR);
CHECK_RETURN_CORE(OK == ParseDatabaseName(env, object, context), RDB_REVT_NOTHING, ERR);
CHECK_RETURN_CORE(OK == ParseDatabasePath(env, object, context), RDB_REVT_NOTHING, ERR);
CHECK_RETURN_CORE(OK == ParseIsSearchable(env, object, context), RDB_REVT_NOTHING, ERR);
return OK;
}
int ParsePath(const napi_env env, const napi_value arg, std::shared_ptr<HelperRdbContext> context)
{
std::string path = JSUtils::Convert2String(env, arg);
CHECK_RETURN_SET(!path.empty(), std::make_shared<ParamError>("name", "a without path non empty string."));
size_t pos = path.find_first_of('/');
CHECK_RETURN_SET(pos == std::string::npos, std::make_shared<ParamError>("name", "a without path without /."));
CHECK_RETURN_SET(context->abilitycontext != nullptr,
std::make_shared<ParamError>("abilitycontext", "abilitycontext is nullptr"));
std::string defaultDir = context->abilitycontext->GetDatabaseDir();
int errorCode = E_OK;
std::string realPath = RdbSqlUtils::GetDefaultDatabasePath(defaultDir, path, errorCode);
CHECK_RETURN_SET(errorCode == E_OK, std::make_shared<ParamError>("config", "a StoreConfig."));
context->config.SetPath(realPath);
return OK;
}
bool IsNapiString(napi_env env, size_t argc, napi_value *argv, size_t arg)
{
if (arg >= argc) {
return false;
}
napi_valuetype type = napi_undefined;
NAPI_CALL_BASE(env, napi_typeof(env, argv[arg], &type), false);
return type == napi_string;
}
using ContextParam = AppDataMgrJsKit::JSUtils::ContextParam;
class DefaultOpenCallback : public RdbOpenCallback {
public:
@ -270,20 +53,32 @@ public:
napi_value GetRdbStore(napi_env env, napi_callback_info info)
{
auto context = std::make_shared<HelperRdbContext>();
struct DeleteContext : public ContextBase {
ContextParam param;
RdbConfig config;
std::shared_ptr<RdbStore> proxy;
};
auto context = std::make_shared<DeleteContext>();
auto input = [context, info](napi_env env, size_t argc, napi_value *argv, napi_value self) {
CHECK_RETURN_SET_E(argc == 2, std::make_shared<ParamNumError>("2 or 3"));
CHECK_RETURN(OK == ParseContext(env, argv[0], context));
CHECK_RETURN(OK == ParseStoreConfig(env, argv[1], context));
int errCode = Convert2Value(env, argv[0], context->param);
CHECK_RETURN_SET_E(OK == errCode, std::make_shared<ParamError>("Illegal context."));
errCode = Convert2Value(env, argv[1], context->config);
CHECK_RETURN_SET_E(OK == errCode, std::make_shared<ParamError>("Illegal StoreConfig or name."));
auto [code, err] = GetRealPath(env, argv[0], context->config, context->param);
CHECK_RETURN_SET_E(OK == code, err);
};
auto exec = [context]() -> int {
int errCode = OK;
DefaultOpenCallback callback;
context->proxy = RdbHelper::GetRdbStore(context->config, -1, callback, errCode);
context->proxy =
RdbHelper::GetRdbStore(GetRdbStoreConfig(context->config, context->param), -1, callback, errCode);
return errCode;
};
auto output = [context](napi_env env, napi_value &result) {
result = RdbStoreProxy::NewInstance(env, context->proxy, context->isSystemAppCalled);
result = RdbStoreProxy::NewInstance(env, context->proxy, context->param.isSystemApp);
CHECK_RETURN_SET_E(result != nullptr, std::make_shared<InnerError>(E_ERROR));
};
context->SetAction(env, info, input, exec, output);
@ -294,18 +89,29 @@ napi_value GetRdbStore(napi_env env, napi_callback_info info)
napi_value DeleteRdbStore(napi_env env, napi_callback_info info)
{
auto context = std::make_shared<HelperRdbContext>();
struct DeleteContext : public ContextBase {
ContextParam param;
RdbConfig config;
};
auto context = std::make_shared<DeleteContext>();
auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
CHECK_RETURN_SET_E(argc == 2, std::make_shared<ParamNumError>("2 or 3"));
CHECK_RETURN(OK == ParseContext(env, argv[0], context));
if (IsNapiString(env, argc, argv, 1)) {
CHECK_RETURN(OK == ParsePath(env, argv[1], context));
int errCode = Convert2Value(env, argv[0], context->param);
CHECK_RETURN_SET_E(OK == errCode, std::make_shared<ParamError>("Illegal context."));
if (IsNapiString(env, argv[1])) {
errCode = Convert2Value(env, argv[1], context->config.name);
CHECK_RETURN_SET_E(OK == errCode, std::make_shared<ParamError>("Illegal path."));
} else {
CHECK_RETURN(OK == ParseStoreConfig(env, argv[1], context));
errCode = Convert2Value(env, argv[1], context->config);
CHECK_RETURN_SET_E(OK == errCode, std::make_shared<ParamError>("Illegal StoreConfig or name."));
}
auto [code, err] = GetRealPath(env, argv[0], context->config, context->param);
CHECK_RETURN_SET_E(OK == code, err);
};
auto exec = [context]() -> int {
return RdbHelper::DeleteRdbStore(context->config.GetPath());
return RdbHelper::DeleteRdbStore(context->config.path);
};
auto output = [context](napi_env env, napi_value &result) {
napi_status status = napi_create_int64(env, OK, &result);

View File

@ -20,11 +20,13 @@
#include <map>
#include <memory>
#include <mutex>
#include <thread>
#include <shared_mutex>
#include <thread>
#include "dataobs_mgr_client.h"
#include "concurrent_map.h"
#include "data_ability_observer_stub.h"
#include "dataobs_mgr_client.h"
#include "rdb_errno.h"
#include "rdb_service.h"
#include "rdb_store.h"
#include "rdb_store_config.h"
@ -32,6 +34,7 @@
#include "sqlite_connection_pool.h"
#include "sqlite_statement.h"
namespace OHOS {
class ExecutorPool;
}
@ -112,8 +115,6 @@ public:
int ExecuteForChangedRowCount(int64_t &outValue, const std::string &sql,
const std::vector<ValueObject> &bindArgs) override;
int Backup(const std::string databasePath, const std::vector<uint8_t> destEncryptKey) override;
int Attach(const std::string &alias, const std::string &pathName,
const std::vector<uint8_t> destEncryptKey) override;
int GetVersion(int &version) override;
int SetVersion(int version) override;
int BeginTransaction() override;
@ -172,6 +173,9 @@ public:
std::vector<PRIKey>& keys) override;
int CleanDirtyData(const std::string &table, uint64_t cursor) override;
std::pair<int32_t, int32_t> Attach(
const RdbStoreConfig &config, const std::string &attachName, int32_t waitTime = 2) override;
std::pair<int32_t, int32_t> Detach(const std::string &attachName, int32_t waitTime = 2) override;
private:
using ExecuteSqls = std::vector<std::pair<std::string, std::vector<std::vector<ValueObject>>>>;
@ -205,6 +209,8 @@ private:
int RegisterDataChangeCallback();
void InitDelayNotifier();
bool ColHasSpecificField(const std::vector<std::string> &columns);
int AttachInner(const std::string &attachName,
const std::string &dbPath, const std::vector<uint8_t> &key, int32_t waitTime);
static constexpr char SCHEME_RDB[] = "rdb://";
static constexpr uint32_t EXPANSION = 2;
@ -236,6 +242,7 @@ private:
std::shared_ptr<std::set<std::string>> syncTables_;
std::map<std::string, std::list<std::shared_ptr<RdbStoreLocalObserver>>> localObservers_;
std::map<std::string, std::list<sptr<RdbStoreLocalSharedObserver>>> localSharedObservers_;
ConcurrentMap<std::string, const RdbStoreConfig> attachedInfo_;
};
} // namespace OHOS::NativeRdb
#endif

View File

@ -62,18 +62,18 @@ public:
int CleanDirtyData(const std::string &table, uint64_t cursor);
int RegisterCallBackObserver(const DataChangeCallback &clientChangedData);
int GetMaxVariableNumber();
JournalMode GetJournalMode();
private:
static constexpr const char *MERGE_ASSETS_FUNC = "merge_assets";
explicit SqliteConnection(bool isWriteConnection);
int InnerOpen(const RdbStoreConfig &config, uint32_t retry);
int GetDbPath(const RdbStoreConfig &config, std::string &dbPath);
int Configure(const RdbStoreConfig &config, uint32_t retry, std::string &dbPath);
int SetPageSize(const RdbStoreConfig &config);
int SetEncryptKey(const RdbStoreConfig &config, uint32_t iter);
int SetJournalMode(const RdbStoreConfig &config);
int SetJournalSizeLimit(const RdbStoreConfig &config);
int SetAutoCheckpoint(const RdbStoreConfig &config);
int SetWalSyncMode(const std::string &syncMode);
int SetSyncMode(const std::string &syncMode);
int PrepareAndBind(const std::string &sql, const std::vector<ValueObject> &bindArgs);
void LimitPermission(const std::string &dbPath) const;
@ -103,6 +103,7 @@ private:
bool isConfigured_ = false;
bool inTransaction_;
bool hasClientObserver_ = false;
JournalMode mode_ = JournalMode::MODE_WAL;
int openFlags;
int maxVariableNumber_;
int32_t id_ = 0;

View File

@ -17,25 +17,31 @@
#define NATIVE_RDB_SQLITE_CONNECTION_POOL_H
#include <condition_variable>
#include <memory>
#include <mutex>
#include <vector>
#include <sstream>
#include <iostream>
#include <iterator>
#include <stack>
#include <list>
#include <memory>
#include <mutex>
#include <sstream>
#include <stack>
#include "base_transaction.h"
#include "rdb_store_config.h"
#include "sqlite_connection.h"
#include "base_transaction.h"
namespace OHOS {
namespace NativeRdb {
class SqliteConnectionPool : public std::enable_shared_from_this<SqliteConnectionPool> {
public:
using SharedConn = std::shared_ptr<SqliteConnection>;
using SharedConns = std::vector<SharedConn>;
static constexpr std::chrono::milliseconds INVALID_TIME = std::chrono::milliseconds(0);
static constexpr int USE_COUNT_MAX = 2;
static std::shared_ptr<SqliteConnectionPool> Create(const RdbStoreConfig &storeConfig, int &errCode);
~SqliteConnectionPool();
std::shared_ptr<SqliteConnection> AcquireConnection(bool isReadOnly);
std::shared_ptr<SqliteConnection> AcquireByID(int32_t id);
SharedConn AcquireConnection(bool isReadOnly);
SharedConn Acquire(bool isReadOnly, std::chrono::milliseconds ms = INVALID_TIME);
std::pair<SharedConn, SharedConns> AcquireAll(int32_t time);
SharedConn AcquireByID(int32_t id);
int RestartReaders();
int ConfigLocale(const std::string &localeStr);
int ChangeDbFileForRestore(const std::string &newPath, const std::string &backupPath,
@ -44,10 +50,13 @@ public:
std::mutex &GetTransactionStackMutex();
int AcquireTransaction();
void ReleaseTransaction();
std::pair<int, SharedConn> DisableWalMode();
int EnableWalMode();
void CloseAllConnections();
private:
struct ConnNode {
bool using_ = false;
uint32_t tid_ = 0;
int32_t tid_ = 0;
int32_t id_ = 0;
std::chrono::steady_clock::time_point time_ = std::chrono::steady_clock::now();
std::shared_ptr<SqliteConnection> connect_;
@ -71,9 +80,11 @@ private:
std::mutex mutex_;
std::condition_variable cond_;
int32_t Initialize(int32_t max, int32_t timeout, Creator creator);
std::pair<int32_t, std::shared_ptr<ConnNode>> Initialize(
int32_t max, int32_t timeout, bool needAcquire, Creator creator);
int32_t ConfigLocale(const std::string &locale);
std::shared_ptr<ConnNode> Acquire();
std::shared_ptr<ConnNode> AcquireById(int32_t id);
std::shared_ptr<ConnNode> Acquire(std::chrono::milliseconds milliS);
int32_t Release(std::shared_ptr<ConnNode> node);
int32_t Clear();
bool IsFull();
@ -82,9 +93,8 @@ private:
explicit SqliteConnectionPool(const RdbStoreConfig &storeConfig);
int Init();
int32_t GetMaxReaders();
int32_t GetMaxReaders(const RdbStoreConfig &config);
void ReleaseNode(std::shared_ptr<ConnNode> node);
void CloseAllConnections();
static constexpr int LIMITATION = 1024;
RdbStoreConfig config_;

View File

@ -18,6 +18,8 @@
#include <string>
#include "rdb_store_config.h"
namespace OHOS {
namespace NativeRdb {
@ -34,14 +36,15 @@ public:
static constexpr int APP_DEFAULT_UMASK = 0002;
static constexpr int SQLITE_MAX_COLUMN = 2000;
static constexpr char ATTACH_BACKUP_SQL[] = "ATTACH ? AS backup KEY ?";
static constexpr char ATTACH_SQL[] = "ATTACH ? AS ? KEY ?";
static constexpr char ATTACH_SQL[] = "ATTACH DATABASE ? AS ? KEY ?";
static constexpr char DETACH_SQL[] = "DETACH DATABASE ?";
static constexpr char EXPORT_SQL[] = "SELECT export_database('backup')";
static constexpr char DETACH_BACKUP_SQL[] = "detach backup";
static constexpr char PRAGMA_JOUR_MODE_EXP[] = "PRAGMA journal_mode";
static constexpr char PRAGMA_VERSION[] = "PRAGMA user_version";
static constexpr char DEFAULT_JOURNAL_MODE[] = "WAL";
static constexpr char DB_DEFAULT_JOURNAL_MODE[] = "DELETE";
static constexpr char WAL_SYNC_MODE[] = "FULL";
static constexpr char JOURNAL_MODE_WAL[] = "WAL";
static constexpr char JOURNAL_MODE_DELETE[] = "DELETE";
static constexpr char DEFAULE_SYNC_MODE[] = "FULL";
static constexpr char MEMORY_DB_PATH[] = ":memory:";
static constexpr char ENCRYPT_ALGO[] = "sha256";
static constexpr char CODEC_HMAC_ALGO[] = "PRAGMA codec_hmac_algo=sha256";
@ -60,10 +63,11 @@ public:
static int GetReadConnectionCount();
static std::string GetMemoryDbPath();
static int GetPageSize();
static std::string GetWalSyncMode();
static std::string GetSyncMode();
static int GetJournalFileSize();
static int GetWalAutoCheckpoint();
static std::string GetDefaultJournalMode();
static int GetDbPath(const RdbStoreConfig &config, std::string &dbPath);
};
} // namespace NativeRdb

View File

@ -22,11 +22,13 @@
#include <mutex>
#include <thread>
#include "concurrent_map.h"
#include "rdb_store.h"
#include "rdb_store_config.h"
#include "sqlite_connection_pool.h"
#include "sqlite_statement.h"
namespace OHOS::NativeRdb {
class RdbStoreImpl : public RdbStore, public std::enable_shared_from_this<RdbStoreImpl> {
public:
@ -65,8 +67,6 @@ public:
int ExecuteForChangedRowCount(int64_t &outValue, const std::string &sql,
const std::vector<ValueObject> &bindArgs) override;
int Backup(const std::string databasePath, const std::vector<uint8_t> destEncryptKey) override;
int Attach(const std::string &alias, const std::string &pathName,
const std::vector<uint8_t> destEncryptKey) override;
int GetVersion(int &version) override;
int SetVersion(int version) override;
int BeginTransaction() override;
@ -91,6 +91,9 @@ public:
int Count(int64_t &outValue, const AbsRdbPredicates &predicates) override;
int Update(int &changedRows, const ValuesBucket &values, const AbsRdbPredicates &predicates) override;
int Delete(int &deletedRows, const AbsRdbPredicates &predicates) override;
std::pair<int32_t, int32_t> Attach(
const RdbStoreConfig &config, const std::string &attachName, int32_t waitTime = 2) override;
std::pair<int32_t, int32_t> Detach(const std::string &attachName, int32_t waitTime = 2) override;
private:
using ExecuteSqls = std::vector<std::pair<std::string, std::vector<std::vector<ValueObject>>>>;
@ -111,6 +114,8 @@ private:
const std::vector<uint8_t> &destEncryptKey = std::vector<uint8_t>());
inline std::string GetSqlArgs(size_t size);
int RegisterDataChangeCallback();
int AttachInner(const std::string &attachName,
const std::string &dbPath, const std::vector<uint8_t> &key, int32_t waitTime);
static constexpr char SCHEME_RDB[] = "rdb://";
static constexpr uint32_t EXPANSION = 2;
@ -120,6 +125,7 @@ private:
const RdbStoreConfig config_;
std::shared_ptr<SqliteConnectionPool> connectionPool_;
ConcurrentMap<std::string, const RdbStoreConfig> attachedInfo_;
bool isOpen_ = false;
bool isReadOnly_;
bool isMemoryRdb_;

View File

@ -63,6 +63,7 @@ public:
int GetMaxVariableNumber();
int32_t GetId() const;
int32_t SetId(int32_t id);
JournalMode GetJournalMode();
private:
static constexpr const char *MERGE_ASSETS_FUNC = "merge_assets";
explicit SqliteConnection(bool isWriteConnection);
@ -74,7 +75,7 @@ private:
int SetJournalMode(const RdbStoreConfig &config);
int SetJournalSizeLimit(const RdbStoreConfig &config);
int SetAutoCheckpoint(const RdbStoreConfig &config);
int SetWalSyncMode(const std::string &syncMode);
int SetSyncMode(const std::string &syncMode);
int PrepareAndBind(const std::string &sql, const std::vector<ValueObject> &bindArgs);
void LimitPermission(const std::string &dbPath) const;
@ -102,6 +103,7 @@ private:
bool isConfigured_ = false;
bool inTransaction_;
bool hasClientObserver_ = false;
JournalMode mode_ = JournalMode::MODE_WAL;
int openFlags;
int maxVariableNumber_;
int32_t id_ = 0;

View File

@ -17,24 +17,32 @@
#define NATIVE_RDB_SQLITE_CONNECTION_POOL_H
#include <condition_variable>
#include <memory>
#include <mutex>
#include <vector>
#include <sstream>
#include <iostream>
#include <iterator>
#include <stack>
#include <list>
#include <memory>
#include <mutex>
#include <sstream>
#include <stack>
#include <vector>
#include "base_transaction.h"
#include "rdb_store_config.h"
#include "sqlite_connection.h"
#include "base_transaction.h"
namespace OHOS {
namespace NativeRdb {
class SqliteConnectionPool : public std::enable_shared_from_this<SqliteConnectionPool> {
public:
using SharedConn = std::shared_ptr<SqliteConnection>;
using SharedConns = std::vector<SharedConn>;
static constexpr std::chrono::milliseconds INVALID_TIME = std::chrono::milliseconds(0);
static constexpr int USE_COUNT_MAX = 2;
static std::shared_ptr<SqliteConnectionPool> Create(const RdbStoreConfig &storeConfig, int &errCode);
~SqliteConnectionPool();
std::shared_ptr<SqliteConnection> AcquireConnection(bool isReadOnly);
SharedConn AcquireConnection(bool isReadOnly);
SharedConn Acquire(bool isReadOnly, std::chrono::milliseconds ms = INVALID_TIME);
std::pair<SharedConn, SharedConns> AcquireAll(int32_t time);
SharedConn AcquireByID(int32_t id);
int RestartReaders();
int ConfigLocale(const std::string &localeStr);
int ChangeDbFileForRestore(const std::string &newPath, const std::string &backupPath,
@ -43,12 +51,14 @@ public:
std::mutex &GetTransactionStackMutex();
int AcquireTransaction();
void ReleaseTransaction();
std::shared_ptr<SqliteConnection> AcquireByID(int32_t id);
std::pair<int, std::shared_ptr<SqliteConnection>> DisableWalMode();
int EnableWalMode();
void CloseAllConnections();
private:
struct ConnNode {
bool using_ = false;
uint32_t tid_ = 0;
uint32_t id_ = 0;
int32_t tid_ = 0;
int32_t id_ = 0;
std::chrono::steady_clock::time_point time_ = std::chrono::steady_clock::now();
std::shared_ptr<SqliteConnection> connect_;
@ -63,28 +73,29 @@ private:
using Creator = std::function<std::pair<int32_t, std::shared_ptr<SqliteConnection>>()>;
int max_ = 0;
int count_ = 0;
uint32_t left_ = 0;
uint32_t right_ = 0;
int32_t left_ = 0;
int32_t right_ = 0;
std::chrono::seconds timeout_;
std::list<std::shared_ptr<ConnNode>> nodes_;
std::list<std::weak_ptr<ConnNode>> details_;
std::mutex mutex_;
std::condition_variable cond_;
int32_t Initialize(int32_t max, int32_t timeout, Creator creator);
std::pair<int32_t, std::shared_ptr<ConnNode>> Initialize(
int32_t max, int32_t timeout, bool needAcquire, Creator creator);
int32_t ConfigLocale(const std::string &locale);
std::shared_ptr<ConnNode> Acquire();
std::shared_ptr<SqliteConnectionPool::ConnNode> AcquireById(int32_t id);
std::shared_ptr<ConnNode> Acquire(std::chrono::milliseconds milliS);
int32_t Release(std::shared_ptr<ConnNode> node);
int32_t Clear();
bool IsFull();
int32_t Dump(const char *header);
std::shared_ptr<SqliteConnectionPool::ConnNode> AcquireById(int32_t id);
};
explicit SqliteConnectionPool(const RdbStoreConfig &storeConfig);
int Init();
int32_t GetMaxReaders();
int32_t GetMaxReaders(const RdbStoreConfig &config);
void ReleaseNode(std::shared_ptr<ConnNode> node);
void CloseAllConnections();
static constexpr int LIMITATION = 1024;
RdbStoreConfig config_;

View File

@ -54,7 +54,7 @@ int RdbHelper::DeleteRdbStore(const std::string &dbFileName)
{
DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
if (dbFileName.empty()) {
return E_EMPTY_FILE_NAME;
return E_INVALID_FILE_PATH;
}
if (access(dbFileName.c_str(), F_OK) != 0) {
return E_OK; // not not exist

View File

@ -42,6 +42,10 @@ RdbStoreConfig::RdbStoreConfig(const std::string &name, StorageMode storageMode,
{
}
RdbStoreConfig::RdbStoreConfig()
{
}
RdbStoreConfig::~RdbStoreConfig()
{
ClearEncryptKey();

View File

@ -1014,33 +1014,36 @@ int RdbStoreImpl::InnerBackup(const std::string &databasePath, const std::vector
if (config_.GetRoleType() == VISITOR) {
return E_NOT_SUPPORT;
}
auto conn = connectionPool_->AcquireConnection(true);
if (conn == nullptr) {
return E_BASE;
}
std::vector<ValueObject> bindArgs;
bindArgs.emplace_back(databasePath);
if (!destEncryptKey.empty() && !isEncrypt_) {
bindArgs.emplace_back(destEncryptKey);
(static_cast<RdbStore *>(this))->ExecuteSql(GlobalExpr::CIPHER_DEFAULT_ATTACH_HMAC_ALGO);
conn->ExecuteSql(GlobalExpr::CIPHER_DEFAULT_ATTACH_HMAC_ALGO);
#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
} else if (isEncrypt_) {
RdbPassword rdbPwd = RdbSecurityManager::GetInstance().GetRdbPassword(
config_.GetPath(), RdbSecurityManager::KeyFileType::PUB_KEY_FILE);
std::vector<uint8_t> key = std::vector<uint8_t>(rdbPwd.GetData(), rdbPwd.GetData() + rdbPwd.GetSize());
bindArgs.emplace_back(key);
(static_cast<RdbStore *>(this))->ExecuteSql(GlobalExpr::CIPHER_DEFAULT_ATTACH_HMAC_ALGO);
conn->ExecuteSql(GlobalExpr::CIPHER_DEFAULT_ATTACH_HMAC_ALGO);
#endif
} else {
std::string str = "";
bindArgs.emplace_back(str);
}
int ret = ExecuteSqlInner(GlobalExpr::ATTACH_BACKUP_SQL, bindArgs);
int ret = conn->ExecuteSql(GlobalExpr::ATTACH_BACKUP_SQL, bindArgs);
if (ret != E_OK) {
return ret;
}
int64_t count;
ret = conn->ExecuteGetLong(count, GlobalExpr::EXPORT_SQL, std::vector<ValueObject>());
ret = ExecuteGetLongInner(GlobalExpr::EXPORT_SQL, std::vector<ValueObject>());
int res = ExecuteSqlInner(GlobalExpr::DETACH_BACKUP_SQL, std::vector<ValueObject>());
int res = conn->ExecuteSql(GlobalExpr::DETACH_BACKUP_SQL, std::vector<ValueObject>());
return res == E_OK ? ret : res;
}
@ -1085,57 +1088,122 @@ bool RdbStoreImpl::IsHoldingConnection()
return connectionPool_ != nullptr;
}
int RdbStoreImpl::AttachInner(
const std::string &attachName, const std::string &dbPath, const std::vector<uint8_t> &key, int32_t waitTime)
{
auto [conn, readers] = connectionPool_->AcquireAll(waitTime);
if (conn == nullptr) {
return E_DATABASE_BUSY;
}
if (conn->GetJournalMode() == JournalMode::MODE_WAL) {
// close first to prevent the connection from being put back.
connectionPool_->CloseAllConnections();
conn = nullptr;
readers.clear();
auto [err, newConn] = connectionPool_->DisableWalMode();
if (err != E_OK) {
return err;
}
conn = newConn;
}
std::vector<ValueObject> bindArgs;
bindArgs.emplace_back(ValueObject(dbPath));
bindArgs.emplace_back(ValueObject(attachName));
if (!key.empty()) {
conn->ExecuteSql(GlobalExpr::CIPHER_DEFAULT_ATTACH_HMAC_ALGO);
bindArgs.emplace_back(ValueObject(key));
}
return conn->ExecuteSql(GlobalExpr::ATTACH_SQL, bindArgs);
}
/**
* Attaches a database.
*/
int RdbStoreImpl::Attach(const std::string &alias, const std::string &pathName,
const std::vector<uint8_t> destEncryptKey)
std::pair<int32_t, int32_t> RdbStoreImpl::Attach(
const RdbStoreConfig &config, const std::string &attachName, int32_t waitTime)
{
std::shared_ptr<SqliteConnection> connection;
std::string sql = GlobalExpr::PRAGMA_JOUR_MODE_EXP;
int errCode = BeginExecuteSql(sql, connection);
if (errCode != 0) {
return errCode;
if (config_.GetRoleType() == VISITOR) {
return { E_NOT_SUPPORT, 0 };
}
std::string journalMode;
errCode = connection->ExecuteGetString(journalMode, sql, std::vector<ValueObject>());
if (errCode != E_OK) {
LOG_ERROR("RdbStoreImpl CheckAttach fail to get journal mode : %d", errCode);
return errCode;
}
journalMode = SqliteUtils::StrToUpper(journalMode);
if (journalMode == GlobalExpr::DEFAULT_JOURNAL_MODE) {
LOG_ERROR("RdbStoreImpl attach is not supported in WAL mode");
return E_NOT_SUPPORTED_ATTACH_IN_WAL_MODE;
std::string dbPath;
int err = SqliteGlobalConfig::GetDbPath(config, dbPath);
if (err != E_OK || access(dbPath.c_str(), F_OK) != E_OK) {
return { E_INVALID_FILE_PATH, 0 };
}
std::vector<ValueObject> bindArgs;
bindArgs.emplace_back(pathName);
bindArgs.emplace_back(alias);
if (!destEncryptKey.empty() && !isEncrypt_) {
bindArgs.emplace_back(destEncryptKey);
(static_cast<RdbStore *>(this))->ExecuteSql(GlobalExpr::CIPHER_DEFAULT_ATTACH_HMAC_ALGO);
// encrypted databases are not supported to attach a non encrypted database.
if (!config.IsEncrypt() && isEncrypt_) {
return { E_NOT_SUPPORTED, 0 };
}
auto iter = attachedInfo_.Find(attachName);
if (iter.first) {
return { E_ATTACHED_DATABASE_EXIST, 0 };
}
std::vector<uint8_t> key;
#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
} else if (isEncrypt_) {
if (config.IsEncrypt()) {
RdbPassword rdbPwd =
RdbSecurityManager::GetInstance().GetRdbPassword(config_.GetPath(),
RdbSecurityManager::KeyFileType::PUB_KEY_FILE);
std::vector<uint8_t> key = std::vector<uint8_t>(rdbPwd.GetData(), rdbPwd.GetData() + rdbPwd.GetSize());
bindArgs.emplace_back(key);
(static_cast<RdbStore *>(this))->ExecuteSql(GlobalExpr::CIPHER_DEFAULT_ATTACH_HMAC_ALGO);
#endif
} else {
std::string str = "";
bindArgs.push_back(ValueObject(str));
RdbSecurityManager::GetInstance().GetRdbPassword(dbPath, RdbSecurityManager::KeyFileType::PUB_KEY_FILE);
key = std::vector<uint8_t>(rdbPwd.GetData(), rdbPwd.GetData() + rdbPwd.GetSize());
}
sql = GlobalExpr::ATTACH_SQL;
errCode = connection->ExecuteSql(sql, bindArgs);
if (errCode != E_OK) {
LOG_ERROR("ExecuteSql ATTACH_SQL error %d", errCode);
#endif
err = AttachInner(attachName, dbPath, key, waitTime);
if (err == SQLITE_ERROR) {
// only when attachName is already in use, SQLITE-ERROR will be reported here.
return { E_ATTACHED_DATABASE_EXIST, 0 };
} else if (err != E_OK) {
LOG_ERROR("failed, errCode[%{public}d] fileName[%{public}s] attachName[%{public}s] attach fileName"
"[%{public}s]",
err, config_.GetName().c_str(), attachName.c_str(), config.GetName().c_str());
return { err, 0 };
}
if (!attachedInfo_.Insert(attachName, config)) {
return { E_ATTACHED_DATABASE_EXIST, 0 };
}
return { E_OK, attachedInfo_.Size() };
}
std::pair<int32_t, int32_t> RdbStoreImpl::Detach(const std::string &attachName, int32_t waitTime)
{
if (config_.GetRoleType() == VISITOR) {
return { E_NOT_SUPPORT, 0 };
}
auto iter = attachedInfo_.Find(attachName);
if (!iter.first) {
return { E_OK, attachedInfo_.Size() };
}
return errCode;
auto [connection, readers] = connectionPool_->AcquireAll(waitTime);
if (connection == nullptr) {
return { E_DATABASE_BUSY, 0 };
}
std::vector<ValueObject> bindArgs;
bindArgs.push_back(ValueObject(attachName));
int err = connection->ExecuteSql(GlobalExpr::DETACH_SQL, bindArgs);
if (err != E_OK) {
LOG_ERROR("failed, errCode[%{public}d] fileName[%{public}s] attachName[%{public}s] attach fileName"
"[%{public}s]",
err, config_.GetName().c_str(), attachName.c_str(), iter.second.GetName().c_str());
return { err, 0 };
}
attachedInfo_.Erase(attachName);
if (!attachedInfo_.Empty()) {
return { E_OK, attachedInfo_.Size() };
}
// close first to prevent the connection from being put back.
connectionPool_->CloseAllConnections();
connection = nullptr;
readers.clear();
err = connectionPool_->EnableWalMode();
if (err != E_OK) {
return { err, 0 };
}
return { E_OK, 0 };
}
/**
@ -1338,7 +1406,7 @@ int RdbStoreImpl::CheckAttach(const std::string &sql)
}
journalMode = SqliteUtils::StrToUpper(journalMode);
if (journalMode == GlobalExpr::DEFAULT_JOURNAL_MODE) {
if (journalMode == GlobalExpr::JOURNAL_MODE_WAL) {
LOG_ERROR("RdbStoreImpl attach is not supported in WAL mode");
return E_NOT_SUPPORTED_ATTACH_IN_WAL_MODE;
}
@ -1910,5 +1978,6 @@ bool RdbStoreImpl::ColHasSpecificField(const std::vector<std::string> &columns)
}
return false;
}
#endif
} // namespace OHOS::NativeRdb

View File

@ -17,6 +17,7 @@
#include <sqlite3sym.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cerrno>
#include <memory>
@ -83,38 +84,10 @@ SqliteConnection::SqliteConnection(bool isWriteConnection)
{
}
int SqliteConnection::GetDbPath(const RdbStoreConfig &config, std::string &dbPath)
{
std::string path;
if (config.GetRoleType() == VISITOR) {
path = config.GetVisitorDir();
} else {
path = config.GetPath();
}
if (config.GetStorageMode() == StorageMode::MODE_MEMORY) {
if (config.GetRoleType() == VISITOR) {
LOG_ERROR("not support MODE_MEMORY, storeName:%{public}s, role:%{public}d", config.GetName().c_str(),
config.GetRoleType());
return E_NOT_SUPPORT;
}
dbPath = SqliteGlobalConfig::GetMemoryDbPath();
} else if (path.empty()) {
LOG_ERROR("SqliteConnection GetDbPath input empty database path");
return E_EMPTY_FILE_NAME;
} else if (path.front() != '/' && path.at(1) != ':') {
LOG_ERROR("SqliteConnection GetDbPath input relative path");
return E_RELATIVE_PATH;
} else {
dbPath = path;
}
return E_OK;
}
int SqliteConnection::InnerOpen(const RdbStoreConfig &config, uint32_t retry)
{
std::string dbPath;
auto ret = GetDbPath(config, dbPath);
auto ret = SqliteGlobalConfig::GetDbPath(config, dbPath);
if (ret != E_OK) {
return ret;
}
@ -478,10 +451,9 @@ int SqliteConnection::RegDefaultFunctions(sqlite3 *dbHandle)
int SqliteConnection::SetJournalMode(const RdbStoreConfig &config)
{
if (isReadOnly || config.GetJournalMode().compare(GlobalExpr::DB_DEFAULT_JOURNAL_MODE) == 0) {
if (isReadOnly) {
return E_OK;
}
std::string currentMode;
int errCode = ExecuteGetString(currentMode, "PRAGMA journal_mode");
if (errCode != E_OK) {
@ -489,6 +461,10 @@ int SqliteConnection::SetJournalMode(const RdbStoreConfig &config)
return errCode;
}
if (config.GetJournalMode().compare(currentMode) == 0) {
return E_OK;
}
currentMode = SqliteUtils::StrToUpper(currentMode);
if (currentMode != config.GetJournalMode()) {
std::string result;
@ -505,9 +481,11 @@ int SqliteConnection::SetJournalMode(const RdbStoreConfig &config)
}
if (config.GetJournalMode() == "WAL") {
errCode = SetWalSyncMode(config.GetSyncMode());
errCode = SetSyncMode(config.GetSyncMode());
}
if (config.GetJournalMode() == "TRUNCATE") {
mode_ = JournalMode::MODE_TRUNCATE;
}
return errCode;
}
@ -563,9 +541,9 @@ int SqliteConnection::SetAutoCheckpoint(const RdbStoreConfig &config)
return errCode;
}
int SqliteConnection::SetWalSyncMode(const std::string &syncMode)
int SqliteConnection::SetSyncMode(const std::string &syncMode)
{
std::string targetValue = SqliteGlobalConfig::GetWalSyncMode();
std::string targetValue = SqliteGlobalConfig::GetSyncMode();
if (syncMode.length() != 0) {
targetValue = syncMode;
}
@ -629,6 +607,7 @@ int SqliteConnection::PrepareAndBind(const std::string &sql, const std::vector<V
errCode = statement.Prepare(dbHandle, sql);
if (errCode != E_OK) {
LOG_ERROR("failed to prepare. code %{public}d", errCode);
return errCode;
}
@ -1012,5 +991,10 @@ int SqliteConnection::GetMaxVariableNumber()
{
return maxVariableNumber_;
}
JournalMode SqliteConnection::GetJournalMode()
{
return mode_;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -32,12 +32,16 @@
namespace OHOS {
namespace NativeRdb {
using namespace OHOS::Rdb;
using ConnPool = SqliteConnectionPool;
using Conn = SqliteConnection;
using SharedConn = std::shared_ptr<SqliteConnection>;
using SharedConns = std::vector<SharedConn>;
constexpr int32_t TRANSACTION_TIMEOUT(2);
std::shared_ptr<SqliteConnectionPool> SqliteConnectionPool::Create(const RdbStoreConfig &storeConfig, int &errCode)
std::shared_ptr<ConnPool> ConnPool::Create(const RdbStoreConfig &storeConfig, int &errCode)
{
std::shared_ptr<SqliteConnectionPool> pool(new (std::nothrow) SqliteConnectionPool(storeConfig));
std::shared_ptr<ConnPool> pool(new (std::nothrow) ConnPool(storeConfig));
if (pool == nullptr) {
LOG_ERROR("SqliteConnectionPool::Create new failed, pool is nullptr");
return nullptr;
@ -49,18 +53,18 @@ std::shared_ptr<SqliteConnectionPool> SqliteConnectionPool::Create(const RdbStor
return pool;
}
SqliteConnectionPool::SqliteConnectionPool(const RdbStoreConfig& storeConfig)
ConnPool::SqliteConnectionPool(const RdbStoreConfig &storeConfig)
: config_(storeConfig), writers_(), readers_(), transactionStack_(), transactionUsed_(false)
{
}
int SqliteConnectionPool::Init()
int ConnPool::Init()
{
if (config_.GetRoleType() == OWNER) {
// write connect count is 1
auto errCode = writers_.Initialize(1, config_.GetWriteTime(), [this]() {
int32_t errCode = E_OK;
auto conn = SqliteConnection::Open(config_, true, errCode);
auto conn = Conn::Open(config_, true, errCode);
return std::pair{ errCode, conn };
});
if (errCode != E_OK) {
@ -68,43 +72,76 @@ int SqliteConnectionPool::Init()
}
}
maxReader_ = GetMaxReaders();
maxReader_ = GetMaxReaders(config_);
// max read connect count is 64
if (maxReader_ > 64) {
return E_ARGS_READ_CON_OVERLOAD;
}
return readers_.Initialize(maxReader_, config_.GetReadTime(), [this]() {
int32_t errCode = E_OK;
auto conn = SqliteConnection::Open(config_, false, errCode);
auto conn = Conn::Open(config_, false, errCode);
return std::pair{ errCode, conn };
});
}
SqliteConnectionPool::~SqliteConnectionPool()
ConnPool::~SqliteConnectionPool()
{
CloseAllConnections();
}
int32_t SqliteConnectionPool::GetMaxReaders()
int32_t ConnPool::GetMaxReaders(const RdbStoreConfig &config)
{
if (config_.GetStorageMode() != StorageMode::MODE_MEMORY && config_.GetJournalMode() == "WAL") {
return config_.GetReadConSize();
if (config.GetStorageMode() != StorageMode::MODE_MEMORY &&
config.GetJournalMode() == GlobalExpr::JOURNAL_MODE_WAL) {
return config.GetReadConSize();
} else {
return 0;
}
}
void SqliteConnectionPool::CloseAllConnections()
void ConnPool::CloseAllConnections()
{
writers_.Clear();
readers_.Clear();
}
std::shared_ptr<SqliteConnection> SqliteConnectionPool::AcquireConnection(bool isReadOnly)
std::shared_ptr<Conn> ConnPool::AcquireConnection(bool isReadOnly)
{
return Acquire(isReadOnly);
}
std::pair<SharedConn, SharedConns> SqliteConnectionPool::AcquireAll(int32_t time)
{
using namespace std::chrono;
std::pair<SharedConn, SharedConns> result;
auto &[writer, readers] = result;
auto interval = duration_cast<milliseconds>(seconds(time));
auto start = steady_clock::now();
writer = Acquire(false, interval);
auto usedTime = duration_cast<milliseconds>(steady_clock::now() - start);
if (writer == nullptr || usedTime >= interval) {
return {};
}
for (int i = 0; i < maxReader_; ++i) {
auto conn = Acquire(true, interval - usedTime);
usedTime = duration_cast<milliseconds>(steady_clock::now() - start);
if (conn == nullptr || usedTime >= interval) {
return {};
}
auto realConn = AcquireByID(conn->GetId());
if (realConn && realConn.use_count() > USE_COUNT_MAX) {
return {};
}
readers.emplace_back(conn);
}
return result;
}
std::shared_ptr<SqliteConnection> SqliteConnectionPool::Acquire(bool isReadOnly, std::chrono::milliseconds ms)
{
Container *container = (isReadOnly && maxReader_ != 0) ? &readers_ : &writers_;
auto node = container->Acquire();
auto node = container->Acquire(ms);
if (node == nullptr) {
const char *header = (isReadOnly && maxReader_ != 0) ? "readers_" : "writers_";
container->Dump(header);
@ -123,7 +160,7 @@ std::shared_ptr<SqliteConnection> SqliteConnectionPool::AcquireConnection(bool i
});
}
std::shared_ptr<SqliteConnection> SqliteConnectionPool::AcquireByID(int32_t id)
std::shared_ptr<Conn> ConnPool::AcquireByID(int32_t id)
{
Container *container = (maxReader_ != 0) ? &readers_ : &writers_;
auto node = container->AcquireById(id);
@ -139,7 +176,7 @@ std::shared_ptr<SqliteConnection> SqliteConnectionPool::AcquireByID(int32_t id)
return conn;
}
void SqliteConnectionPool::ReleaseNode(std::shared_ptr<ConnNode> node)
void ConnPool::ReleaseNode(std::shared_ptr<ConnNode> node)
{
if (node == nullptr) {
return;
@ -152,7 +189,7 @@ void SqliteConnectionPool::ReleaseNode(std::shared_ptr<ConnNode> node)
}
}
int SqliteConnectionPool::AcquireTransaction()
int ConnPool::AcquireTransaction()
{
std::unique_lock<std::mutex> lock(transMutex_);
if (transCondition_.wait_for(lock, std::chrono::seconds(TRANSACTION_TIMEOUT), [this] {
@ -165,7 +202,7 @@ int SqliteConnectionPool::AcquireTransaction()
return E_TRANSACTION_IN_EXECUTE;
}
void SqliteConnectionPool::ReleaseTransaction()
void ConnPool::ReleaseTransaction()
{
{
std::unique_lock<std::mutex> lock(transMutex_);
@ -174,12 +211,12 @@ void SqliteConnectionPool::ReleaseTransaction()
transCondition_.notify_one();
}
int SqliteConnectionPool::RestartReaders()
int ConnPool::RestartReaders()
{
readers_.Clear();
return readers_.Initialize(maxReader_, config_.GetReadTime(), [this]() {
int32_t errCode = E_OK;
auto conn = SqliteConnection::Open(config_, false, errCode);
auto conn = Conn::Open(config_, false, errCode);
return std::pair{ errCode, conn };
});
}
@ -187,7 +224,7 @@ int SqliteConnectionPool::RestartReaders()
/**
* The database locale.
*/
int SqliteConnectionPool::ConfigLocale(const std::string &localeStr)
int ConnPool::ConfigLocale(const std::string &localeStr)
{
auto errCode = readers_.ConfigLocale(localeStr);
if (errCode != E_OK) {
@ -199,8 +236,8 @@ int SqliteConnectionPool::ConfigLocale(const std::string &localeStr)
/**
* Rename the backed up database.
*/
int SqliteConnectionPool::ChangeDbFileForRestore(const std::string &newPath, const std::string &backupPath,
const std::vector<uint8_t> &newKey)
int ConnPool::ChangeDbFileForRestore(
const std::string &newPath, const std::string &backupPath, const std::vector<uint8_t> &newKey)
{
if (!writers_.IsFull() || !readers_.IsFull()) {
LOG_ERROR("Connection pool is busy now!");
@ -231,19 +268,52 @@ int SqliteConnectionPool::ChangeDbFileForRestore(const std::string &newPath, con
return Init();
}
std::stack<BaseTransaction> &SqliteConnectionPool::GetTransactionStack()
std::stack<BaseTransaction> &ConnPool::GetTransactionStack()
{
return transactionStack_;
}
std::mutex &SqliteConnectionPool::GetTransactionStackMutex()
std::mutex &ConnPool::GetTransactionStackMutex()
{
return transactionStackMutex_;
}
SqliteConnectionPool::ConnNode::ConnNode(std::shared_ptr<SqliteConnection> conn) : connect_(std::move(conn)) {}
std::pair<int, std::shared_ptr<Conn>> ConnPool::DisableWalMode()
{
auto [errCode, node] = writers_.Initialize(1, config_.GetWriteTime(), true, [this]() {
int32_t errCode = E_OK;
RdbStoreConfig config = config_;
config.SetJournalMode(JournalMode::MODE_TRUNCATE);
maxReader_ = GetMaxReaders(config);
auto conn = Conn::Open(config, true, errCode);
return std::pair{ errCode, conn };
});
if (errCode != E_OK) {
return { errCode, nullptr };
}
auto conn = node->GetConnect();
if (conn == nullptr) {
return { E_ERROR, nullptr };
}
auto result =
std::shared_ptr<Conn>(conn.get(), [pool = weak_from_this(), hold = node](Conn *) {
auto realPool = pool.lock();
if (realPool == nullptr) {
return;
}
realPool->ReleaseNode(hold);
});
return { E_OK, std::move(result) };
}
std::shared_ptr<SqliteConnection> SqliteConnectionPool::ConnNode::GetConnect(bool justHold)
int ConnPool::EnableWalMode()
{
return Init();
}
ConnPool::ConnNode::ConnNode(std::shared_ptr<Conn> conn) : connect_(std::move(conn)) {}
std::shared_ptr<Conn> ConnPool::ConnNode::GetConnect(bool justHold)
{
if (!justHold) {
tid_ = gettid();
@ -252,13 +322,13 @@ std::shared_ptr<SqliteConnection> SqliteConnectionPool::ConnNode::GetConnect(boo
return connect_;
}
int64_t SqliteConnectionPool::ConnNode::GetUsingTime() const
int64_t ConnPool::ConnNode::GetUsingTime() const
{
auto time = std::chrono::steady_clock::now() - time_;
return std::chrono::duration_cast<std::chrono::milliseconds>(time).count();
}
void SqliteConnectionPool::ConnNode::Unused()
void ConnPool::ConnNode::Unused()
{
tid_ = 0;
time_ = std::chrono::steady_clock::now();
@ -268,7 +338,7 @@ void SqliteConnectionPool::ConnNode::Unused()
}
}
bool SqliteConnectionPool::ConnNode::IsWriter() const
bool ConnPool::ConnNode::IsWriter() const
{
if (connect_ != nullptr) {
return connect_->IsWriteConnection();
@ -276,7 +346,14 @@ bool SqliteConnectionPool::ConnNode::IsWriter() const
return false;
}
int32_t SqliteConnectionPool::Container::Initialize(int32_t max, int32_t timeout, Creator creator)
int32_t ConnPool::Container::Initialize(int32_t max, int32_t timeout, Creator creator)
{
auto [errCode, node] = Initialize(max, timeout, false, std::move(creator));
return errCode;
}
std::pair<int32_t, std::shared_ptr<ConnPool::ConnNode>> ConnPool::Container::Initialize(
int32_t max, int32_t timeout, bool needAcquire, Creator creator)
{
std::unique_lock<decltype(mutex_)> lock(mutex_);
for (int i = 0; i < max; ++i) {
@ -284,7 +361,7 @@ int32_t SqliteConnectionPool::Container::Initialize(int32_t max, int32_t timeout
if (conn == nullptr) {
nodes_.clear();
details_.clear();
return error;
return { error, nullptr };
}
auto node = std::make_shared<ConnNode>(conn);
node->id_ = right_++;
@ -295,10 +372,16 @@ int32_t SqliteConnectionPool::Container::Initialize(int32_t max, int32_t timeout
max_ = max;
count_ = max;
timeout_ = std::chrono::seconds(timeout);
return E_OK;
std::shared_ptr<ConnNode> connNode = nullptr;
if (needAcquire) {
connNode = nodes_.back();
nodes_.pop_back();
count_--;
}
return { E_OK, connNode };
}
int32_t SqliteConnectionPool::Container::ConfigLocale(const std::string& locale)
int32_t ConnPool::Container::ConfigLocale(const std::string& locale)
{
std::unique_lock<decltype(mutex_)> lock(mutex_);
if (max_ != count_) {
@ -315,10 +398,11 @@ int32_t SqliteConnectionPool::Container::ConfigLocale(const std::string& locale)
return E_OK;
}
std::shared_ptr<SqliteConnectionPool::ConnNode> SqliteConnectionPool::Container::Acquire()
std::shared_ptr<ConnPool::ConnNode> ConnPool::Container::Acquire(std::chrono::milliseconds milliS)
{
auto interval = (milliS == INVALID_TIME) ? timeout_ : milliS;
std::unique_lock<decltype(mutex_)> lock(mutex_);
if (cond_.wait_for(lock, timeout_, [this] { return count_ > 0; })) {
if (cond_.wait_for(lock, interval, [this] { return count_ > 0; })) {
auto node = nodes_.back();
nodes_.pop_back();
count_--;
@ -327,7 +411,7 @@ std::shared_ptr<SqliteConnectionPool::ConnNode> SqliteConnectionPool::Container:
return nullptr;
}
std::shared_ptr<SqliteConnectionPool::ConnNode> SqliteConnectionPool::Container::AcquireById(int32_t id)
std::shared_ptr<ConnPool::ConnNode> ConnPool::Container::AcquireById(int32_t id)
{
for (auto& detail : details_) {
auto node = detail.lock();
@ -341,21 +425,21 @@ std::shared_ptr<SqliteConnectionPool::ConnNode> SqliteConnectionPool::Container:
return nullptr;
}
int32_t SqliteConnectionPool::Container::Release(std::shared_ptr<ConnNode> node)
int32_t ConnPool::Container::Release(std::shared_ptr<ConnNode> node)
{
{
std::unique_lock<decltype(mutex_)> lock(mutex_);
if (node->id_ < left_ || node->id_ >= right_) {
return E_OK;
}
nodes_.push_back(node);
nodes_.push_front(node);
count_++;
}
cond_.notify_one();
return E_OK;
}
int32_t SqliteConnectionPool::Container::Clear()
int32_t ConnPool::Container::Clear()
{
std::list<std::shared_ptr<ConnNode>> nodes;
std::list<std::weak_ptr<ConnNode>> details;
@ -372,13 +456,13 @@ int32_t SqliteConnectionPool::Container::Clear()
return 0;
}
bool SqliteConnectionPool::Container::IsFull()
bool ConnPool::Container::IsFull()
{
std::unique_lock<decltype(mutex_)> lock(mutex_);
return max_ == count_;
}
int32_t SqliteConnectionPool::Container::Dump(const char *header)
int32_t ConnPool::Container::Dump(const char *header)
{
std::string info;
for (auto& detail : details_) {

View File

@ -22,6 +22,7 @@
#include "logger.h"
#include "sqlite3sym.h"
#include "sqlite_utils.h"
#include "rdb_errno.h"
namespace OHOS {
namespace NativeRdb {
@ -78,9 +79,9 @@ int SqliteGlobalConfig::GetPageSize()
return GlobalExpr::DB_PAGE_SIZE;
}
std::string SqliteGlobalConfig::GetWalSyncMode()
std::string SqliteGlobalConfig::GetSyncMode()
{
return GlobalExpr::WAL_SYNC_MODE;
return GlobalExpr::DEFAULE_SYNC_MODE;
}
int SqliteGlobalConfig::GetJournalFileSize()
@ -95,7 +96,32 @@ int SqliteGlobalConfig::GetWalAutoCheckpoint()
std::string SqliteGlobalConfig::GetDefaultJournalMode()
{
return GlobalExpr::DEFAULT_JOURNAL_MODE;
return GlobalExpr::JOURNAL_MODE_WAL;
}
int SqliteGlobalConfig::GetDbPath(const RdbStoreConfig &config, std::string &dbPath)
{
std::string path;
if (config.GetRoleType() == VISITOR) {
path = config.GetVisitorDir();
} else {
path = config.GetPath();
}
if (config.GetStorageMode() == StorageMode::MODE_MEMORY) {
if (config.GetRoleType() == VISITOR) {
LOG_ERROR("not support MODE_MEMORY, storeName:%{public}s, role:%{public}d", config.GetName().c_str(),
config.GetRoleType());
return E_NOT_SUPPORT;
}
dbPath = SqliteGlobalConfig::GetMemoryDbPath();
} else if (path.empty() || (path.front() != '/' && path.at(1) != ':')) {
LOG_ERROR("SqliteConnection GetDbPath input empty database path");
return E_INVALID_FILE_PATH;
} else {
dbPath = path;
}
return E_OK;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -85,9 +85,9 @@ constexpr int E_INVALID_COLUMN_INDEX = (E_BASE + 8);
constexpr int E_INVALID_COLUMN_TYPE = (E_BASE + 9);
/**
* @brief The error code for a file name is empty.
* @brief The error for the database corrupted.
*/
constexpr int E_EMPTY_FILE_NAME = (E_BASE + 10);
constexpr int E_DATA_BASE_CORRUPTED = (E_BASE + 10);
/**
* @brief The error for the current file path is invalid.
@ -205,9 +205,9 @@ constexpr int E_EMPTY_NEW_ENCRYPT_KEY = (E_BASE + 32);
constexpr int E_CHANGE_UNENCRYPTED_TO_ENCRYPTED = (E_BASE + 33);
/**
* @brief The error code for change encrypt in busy.
* @brief The error code for database busy.
*/
constexpr int E_CHANGE_ENCRYPT_KEY_IN_BUSY = (E_BASE + 34);
constexpr int E_DATABASE_BUSY = (E_BASE + 34);
/**
* @brief The error code when the statement not initialized.
@ -303,6 +303,11 @@ static constexpr int E_DATABASE_FULL = (E_BASE + 52);
* @brief The error when sql is not supported in execute
*/
static constexpr int E_NOT_SUPPORT_THE_SQL = (E_BASE + 53);
/**
* @brief The database is already attached.
*/
static constexpr int E_ATTACHED_DATABASE_EXIST = (E_BASE + 54);
} // namespace NativeRdb
} // namespace OHOS

View File

@ -16,6 +16,7 @@
#ifndef NATIVE_RDB_RDB_STORE_H
#define NATIVE_RDB_RDB_STORE_H
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
@ -28,6 +29,7 @@
#include "rdb_types.h"
#include "rdb_common.h"
#include "rdb_errno.h"
#include "rdb_store_config.h"
namespace OHOS::NativeRdb {
class API_EXPORT RdbStore {
@ -324,11 +326,16 @@ public:
* @brief Attaches a database.
*
* @param alias Indicates the database alias.
* @param databasePath Indicates the database file pathname.
* @param pathName Indicates the database file pathname.
* @param destEncryptKey Indicates the database encrypt key.
*/
[[deprecated("Use Attach(const RdbStoreConfig &config, const std::string &attachName, int32_t waitTime = 2) "
"instead.")]]
virtual int Attach(
const std::string &alias, const std::string &pathName, const std::vector<uint8_t> destEncryptKey) = 0;
const std::string &alias, const std::string &pathName, const std::vector<uint8_t> destEncryptKey)
{
return E_OK;
}
/**
* @brief Get the value of the column based on specified conditions.
@ -565,6 +572,30 @@ public:
* @param table Indicates the specified table.
*/
virtual int CleanDirtyData(const std::string &table, uint64_t cursor = UINT64_MAX) = 0;
/**
* @brief Attaches a database file to the currently linked database.
*
* @param config Indicates the {@link RdbStoreConfig} configuration of the database related to this RDB store.
* @param attachName Indicates the alias of the database.
* @param waitTime Indicates the maximum time allowed for attaching the database file.
*/
virtual std::pair<int32_t, int32_t> Attach(
const RdbStoreConfig &config, const std::string &attachName, int32_t waitTime = 2)
{
return std::pair<int32_t, int32_t>(0, E_OK);
}
/**
* @brief Detaches a database from this database.
*
* @param attachName Indicates the alias of the database.
* @param waitTime Indicates the maximum time allowed for attaching the database file.
*/
virtual std::pair<int32_t, int32_t> Detach(const std::string &attachName, int32_t waitTime = 2)
{
return std::pair<int32_t, int32_t>(0, E_OK);
}
};
} // namespace OHOS::NativeRdb
#endif

View File

@ -186,7 +186,7 @@ public:
const std::string &databaseFileType = "", SecurityLevel securityLevel = SecurityLevel::LAST,
bool isCreateNecessary = true, bool autoCheck = false, int journalSize = DB_JOURNAL_SIZE,
int pageSize = DB_PAGE_SIZE, const std::string &encryptAlgo = DB_DEFAULT_ENCRYPT_ALGO);
RdbStoreConfig();
/**
* @brief Destructor.
*/

View File

@ -21,12 +21,13 @@
#include <vector>
#include "abs_rdb_predicates.h"
#include "rdb_common.h"
#include "rdb_errno.h"
#include "rdb_store_config.h"
#include "rdb_types.h"
#include "result_set.h"
#include "value_object.h"
#include "values_bucket.h"
#include "rdb_common.h"
#include "rdb_types.h"
namespace OHOS::NativeRdb {
class RdbStore {
public:
@ -75,7 +76,10 @@ public:
const std::vector<ValueObject> &bindArgs = {}) = 0;
virtual int Backup(const std::string databasePath, const std::vector<uint8_t> destEncryptKey = {}) = 0;
virtual int Attach(
const std::string &alias, const std::string &pathName, const std::vector<uint8_t> destEncryptKey) = 0;
const std::string &alias, const std::string &pathName, const std::vector<uint8_t> destEncryptKey)
{
return E_OK;
}
virtual int Count(int64_t &outValue, const AbsRdbPredicates &predicates) = 0;
virtual std::shared_ptr<ResultSet> Query(
@ -95,6 +99,9 @@ public:
virtual bool IsReadOnly() const = 0;
virtual bool IsMemoryRdb() const = 0;
virtual int Restore(const std::string backupPath, const std::vector<uint8_t> &newKey = {}) = 0;
virtual std::pair<int32_t, int32_t> Attach(
const RdbStoreConfig &config, const std::string &attachName, int32_t waitTime = 2) = 0;
virtual std::pair<int32_t, int32_t> Detach(const std::string &attachName, int32_t waitTime = 2) = 0;
};
} // namespace OHOS::NativeRdb
#endif

View File

@ -85,6 +85,7 @@ public:
SecurityLevel securityLevel = SecurityLevel::LAST, bool isCreateNecessary = true,
bool autoCheck = false, int journalSize = 1048576, int pageSize = 4096,
const std::string &encryptAlgo = "sha256");
RdbStoreConfig();
~RdbStoreConfig();
std::string GetName() const;
std::string GetPath() const;

View File

@ -0,0 +1,458 @@
/*
* 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_JSKITS_TEST]"
const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT NOT NULL, " + "age INTEGER, " + "salary REAL, " + "blobType BLOB)";
const CREATE_TABLE_TEST1 = "CREATE TABLE IF NOT EXISTS test1 (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT NOT NULL, " + "age INTEGER, " + "salary REAL, " + "blobType BLOB)";
const STORE_CONFIG = {
name: "rdbstore.db",
securityLevel: data_relationalStore.SecurityLevel.S1,
}
const STORE_CONFIG1 = {
name: "rdbstore1.db",
securityLevel: data_relationalStore.SecurityLevel.S1,
}
const STORE_CONFIG2 = {
name: "rdbstore2.db",
encrypt: true,
securityLevel: data_relationalStore.SecurityLevel.S1,
}
const STORE_CONFIG3 = {
name: "rdbstore3.db",
encrypt: true,
securityLevel: data_relationalStore.SecurityLevel.S1,
}
describe('ActsRdbStoreAttachTest', function () {
beforeAll(async function () {
console.info(TAG + 'beforeAll');
})
beforeEach(async function () {
console.info(TAG + 'beforeEach');
let attachStore = await data_relationalStore.getRdbStore(context, STORE_CONFIG1);
await attachStore.executeSql(CREATE_TABLE_TEST1);
let attachStore1 = await data_relationalStore.getRdbStore(context, STORE_CONFIG2);
await attachStore1.executeSql(CREATE_TABLE_TEST1);
})
afterEach(async function () {
console.info(TAG + 'afterEach')
await data_relationalStore.deleteRdbStore(context, "rdbstore.db");
await data_relationalStore.deleteRdbStore(context, "rdbstore1.db");
await data_relationalStore.deleteRdbStore(context, "rdbstore2.db");
await data_relationalStore.deleteRdbStore(context, "rdbstore3.db");
})
afterAll(async function () {
console.info(TAG + 'afterAll');
})
async function attachInsert(store, tableName) {
var u8 = new Uint8Array([1, 2, 3])
const valueBucket = {
"name": "zhangsan",
"age": 18,
"salary": 100.5,
"blobType": u8,
};
await store.insert(tableName, valueBucket);
}
async function attachBatchInsert(store, tableName) {
var u8 = new Uint8Array([1, 2, 3])
const valueBucket = {
"name": "zhangsan",
"age": 18,
"salary": 100.5,
"blobType": u8,
};
let valueBucketArray = new Array();
for (let i = 0; i < 10; i++) {
valueBucketArray.push(valueBucket);
}
await store.batchInsert(tableName, valueBucketArray);
}
async function insertCheck(store, tableName, ret) {
let predicates = new data_relationalStore.RdbPredicates(tableName);
let resultSet = await store.query(predicates);
let count = resultSet.rowCount;
expect(ret).assertEqual(count);
resultSet.close();
}
async function updateCheck(store, tableName) {
var u8 = new Uint8Array([4, 5, 6]);
const valueBucket = {
"name": "lisi",
"age": 20,
"salary": 200.5,
"blobType": u8,
};
let predicates = new data_relationalStore.RdbPredicates(tableName)
predicates.equalTo("id", "1");
let ret = await store.update(valueBucket, predicates);
expect(1).assertEqual(ret);
}
async function deleteCheck(store, tableName, count) {
let predicates = new data_relationalStore.RdbPredicates(tableName);
let ret = await store.delete(predicates);
expect(count).assertEqual(ret);
}
async function attachCheck(store) {
await attachInsert(store, "test");
await insertCheck(store, "test", 2);
await updateCheck(store, "test");
await attachBatchInsert(store, "test");
await insertCheck(store, "test", 12);
await deleteCheck(store, "test", 12);
await attachInsert(store, "test1");
await insertCheck(store, "test1", 1)
await updateCheck(store, "test1");
await attachBatchInsert(store, "test1");
await insertCheck(store, "test1", 11);
await deleteCheck(store, "test1", 11);
}
console.log(TAG + "*************Unit Test Begin*************");
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_001
* @tc.desc non encrypted database attach non encrypted database
*/
it('testRdbStoreAttach0001', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach0001 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachInsert(store, "test");
let number = await store.attach(context, STORE_CONFIG1, "attachDB");
expect(1).assertEqual(number);
await attachCheck(store);
expect(0).assertEqual(await store.detach("attachDB"))
console.log(TAG + "************* testRdbStoreAttach0001 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_002
* @tc.desc non encrypted database attach encrypted database
*/
it('testRdbStoreAttach0002', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach0002 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachInsert(store, "test");
let number = await store.attach(context, STORE_CONFIG2, "attachDB");
expect(1).assertEqual(number);
await attachCheck(store);
expect(0).assertEqual(await store.detach("attachDB"))
console.log(TAG + "************* testRdbStoreAttach0002 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_003
* @tc.desc encrypted database attach encrypted database
*/
it('testRdbStoreAttach0003', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach0003 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG3);
await store.executeSql(CREATE_TABLE_TEST);
await attachInsert(store, "test");
let number = await store.attach(context, STORE_CONFIG2, "attachDB");
expect(1).assertEqual(number);
await attachCheck(store);
expect(0).assertEqual(await store.detach("attachDB"));
console.log(TAG + "************* testRdbStoreAttach0003 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_004
* @tc.desc encrypted databases are not supported for attaching non encrypted databases
*/
it('testRdbStoreAttach0004', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach0004 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG3);
try {
await store.attach(context, STORE_CONFIG1, "attachDB");
expect().assertFail();
} catch(e) {
console.log("attach err: failed, err: code=" + e.code + " message=" + e.message)
expect(801).assertEqual(e.code);
}
console.log(TAG + "************* testRdbStoreAttach0004 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_005
* @tc.desc non encrypted database attach non encrypted database
*/
it('testRdbStoreAttach0005', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach0005 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachInsert(store, "test");
let number = await store.attach("/data/storage/el2/database/entry/rdb/rdbstore1.db", "attachDB");
expect(1).assertEqual(number);
await attachCheck(store);
expect(0).assertEqual(await store.detach("attachDB"));
console.log(TAG + "************* testRdbStoreAttach0005 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_006
* @tc.desc path error for non encrypted database
*/
it('testRdbStoreAttach0006', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach0006 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachInsert(store, "test");
let STORE_CONFIG4 = {
name: "/wrong/rdbstore.db",
securityLevel: data_relationalStore.SecurityLevel.S1,
}
try {
await store.attach(context, STORE_CONFIG4, "attachDB");
} catch (e) {
console.log("catch err: failed, err: code=" + e.code + " message=" + e.message)
expect("401").assertEqual(e.code);
}
console.log(TAG + "************* testRdbStoreAttach0006 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_007
* @tc.desc non encrypted database attach non encrypted database with same table name
*/
it('testRdbStoreAttach0007', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach0007 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST1);
await attachInsert(store, "test1");
let number = await store.attach(context, STORE_CONFIG1, "attachDB");
expect(1).assertEqual(number);
await attachInsert(store, "test1");
await insertCheck(store, "test1", 2);
await updateCheck(store, "test1");
await attachBatchInsert(store, "test1");
await insertCheck(store, "test1", 12);
await deleteCheck(store, "test1", 12);
await attachInsert(store, "attachDB.test1");
await insertCheck(store, "attachDB.test1", 1)
await updateCheck(store, "attachDB.test1");
await attachBatchInsert(store, "attachDB.test1");
await insertCheck(store, "attachDB.test1", 11);
await deleteCheck(store, "attachDB.test1", 11);
expect(0).assertEqual(await store.detach("attachDB"))
console.log(TAG + "************* testRdbStoreAttach0007 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_008
* @tc.desc resultSet occupies connection, attach failed
*/
it('testRdbStoreAttach0008', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach0008 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachBatchInsert(store, "test");
let predicates = new data_relationalStore.RdbPredicates("test");
let resultSet = await store.query(predicates);
let count = resultSet.rowCount;
expect(10).assertEqual(count);
try {
await store.attach("/data/storage/el2/database/entry/rdb/rdbstore1.db", "attachDB");
expect().assertFail();
} catch(e) {
expect(14800015).assertEqual(e.code);
}
resultSet.close();
console.log(TAG + "************* testRdbStoreAttach0008 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_009
* @tc.desc repeat attach using the same alias
*/
it('testRdbStoreAttach0009', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach0009 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachBatchInsert(store, "test");
let number = await store.attach(context, STORE_CONFIG1, 'attachDB');
expect(1).assertEqual(number);
try {
await store.attach(context, STORE_CONFIG1, 'attachDB');
expect().assertFail();
} catch(e) {
console.log("testRdbStoreAttach0009: failed, err: code=" + e.code + " message=" + e.message);
expect(14800016).assertEqual(e.code);
}
expect(0).assertEqual(await store.detach("attachDB"));
console.log(TAG + "************* testRdbStoreAttach0009 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_0010
* @tc.desc WaitTime exceeds maximum limit
*/
it('testRdbStoreAttach00010', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach00010 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachBatchInsert(store, "test");
let number = await store.attach(context, STORE_CONFIG1, 'attachDB', 300);
expect(1).assertEqual(number);
try {
await store.attach(context, STORE_CONFIG1, 'attachDB', 301);
expect().assertFail();
} catch(e) {
console.log("testRdbStoreAttach00010: failed, err: code=" + e.code + " message=" + e.message);
expect("401").assertEqual(e.code);
}
expect(0).assertEqual(await store.detach("attachDB"));
console.log(TAG + "************* testRdbStoreAttach00010 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_0011
* @tc.desc WaitTime exceeds the minimum limit
*/
it('testRdbStoreAttach00011', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach00011 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachBatchInsert(store, "test");
let number = await store.attach(context, STORE_CONFIG1, 'attachDB', 1);
expect(1).assertEqual(number);
try {
await store.attach(context, STORE_CONFIG1, 'attachDB', -1);
expect().assertFail();
} catch(e) {
console.log("testRdbStoreAttach00011: failed, err: code=" + e.code + " message=" + e.message);
expect('401').assertEqual(e.code);
}
expect(0).assertEqual(await store.detach("attachDB"));
console.log(TAG + "************* testRdbStoreAttach00011 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_0012
* @tc.desc the alias cannot be empty
*/
it('testRdbStoreAttach00012', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach00012 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachBatchInsert(store, "test");
try {
await store.attach(context, STORE_CONFIG1, '');
expect().assertFail();
} catch(e) {
console.log("testRdbStoreAttach00012 : failed, err: code=" + e.code + " message=" + e.message);
expect('401').assertEqual(e.code);
}
console.log(TAG + "************* testRdbStoreAttach00012 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_0013
* @tc.desc input error path
*/
it('testRdbStoreAttach00013', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach00013 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachBatchInsert(store, "test");
try {
await store.attach("/path/errPath/attach.db", "attachDB");
expect().assertFail();
} catch(e) {
console.log("testRdbStoreAttach00013 : failed, err: code=" + e.code + " message=" + e.message);
expect(14800010).assertEqual(e.code);
}
console.log(TAG + "************* testRdbStoreAttach00013 end *************");
})
/**
* @tc.name the attach function
* @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_attach_0014
* @tc.desc input empty path
*/
it('testRdbStoreAttach00014', 0, async function () {
console.log(TAG + "************* testRdbStoreAttach00014 start *************");
let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG);
await store.executeSql(CREATE_TABLE_TEST);
await attachBatchInsert(store, "test");
try {
await store.attach("", "attachDB");
expect().assertFail();
} catch(e) {
console.log("testRdbStoreAttach00014 : failed, err: code=" + e.code + " message=" + e.message);
expect('401').assertEqual(e.code);
}
console.log(TAG + "************* testRdbStoreAttach00014 end *************");
})
console.log(TAG + "*************Unit Test End*************");
})

View File

@ -33,13 +33,16 @@ public:
void TearDown();
void QueryCheck1(std::shared_ptr<RdbStore> &store) const;
void QueryCheck2(std::shared_ptr<RdbStore> &store) const;
void DeleteCheck(std::shared_ptr<RdbStore> &store) const;
void UpdateCheck(std::shared_ptr<RdbStore> &store) const;
void InsertCheck(std::shared_ptr<RdbStore> &store) const;
static const std::string MAIN_DATABASE_NAME;
static const std::string ATTACHED_DATABASE_NAME;
static constexpr const char *MAIN_DATABASE_NAME = "/data/test/main.db";
static constexpr const char *ATTACHED_DATABASE_NAME = "/data/test/attached.db";
static constexpr const char *ENCRYPT_ATTACHED_DATABASE_NAME = "/data/test/encrypt_attached.db";
static constexpr int BUSY_TIMEOUT = 2;
};
const std::string RdbAttachTest::MAIN_DATABASE_NAME = RDB_TEST_PATH + "main.db";
class MainOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &store) override;
@ -60,8 +63,6 @@ int MainOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
return E_OK;
}
const std::string RdbAttachTest::ATTACHED_DATABASE_NAME = RDB_TEST_PATH + "attached.db";
class AttachedOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &store) override;
@ -119,7 +120,7 @@ HWTEST_F(RdbAttachTest, RdbStore_Attach_001, TestSize.Level1)
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
int ret = store->ExecuteSql("ATTACH '" + ATTACHED_DATABASE_NAME + "' as attached");
int ret = store->ExecuteSql("ATTACH '" + std::string(ATTACHED_DATABASE_NAME) + "' as attached");
EXPECT_EQ(ret, E_NOT_SUPPORTED_ATTACH_IN_WAL_MODE);
}
@ -137,23 +138,10 @@ HWTEST_F(RdbAttachTest, RdbStore_Attach_002, TestSize.Level1)
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
int ret = store->ExecuteSql("ATTACH DATABASE '" + ATTACHED_DATABASE_NAME + "' as 'attached'");
int ret = store->ExecuteSql("ATTACH DATABASE '" + std::string(ATTACHED_DATABASE_NAME) + "' as 'attached'");
EXPECT_EQ(ret, E_OK);
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
ret = store->Insert(id, "test1", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(id, 1);
values.Clear();
values.PutInt("id", 1);
values.PutString("name", std::string("lisi"));
ret = store->Insert(id, "test2", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(id, 1);
InsertCheck(store);
QueryCheck1(store);
@ -162,23 +150,21 @@ HWTEST_F(RdbAttachTest, RdbStore_Attach_002, TestSize.Level1)
QueryCheck2(store);
ret = store->ExecuteSql("attach database '" + ATTACHED_DATABASE_NAME + "' as 'attached'");
ret = store->ExecuteSql("attach database '" + std::string(ATTACHED_DATABASE_NAME) + "' as 'attached'");
EXPECT_EQ(ret, E_OK);
ret = store->ExecuteSql("detach database 'attached'");
EXPECT_EQ(ret, E_OK);
}
/* *
/**
* @tc.name: RdbStore_Attach_003
* @tc.desc: Abnormal testCase for Attach
* @tc.type: FUNC
*/
HWTEST_F(RdbAttachTest, RdbStore_Attach_003, TestSize.Level2)
{
const std::string alias = "attached";
std::vector<uint8_t> destEncryptKey;
const std::string attachedName = "attached";
RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
MainOpenCallback helper;
int errCode = E_OK;
@ -187,33 +173,113 @@ HWTEST_F(RdbAttachTest, RdbStore_Attach_003, TestSize.Level2)
std::shared_ptr<RdbStore> store1 = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(nullptr, store1);
EXPECT_EQ(E_OK, errCode);
RdbStoreConfig attachedConfig(RdbAttachTest::ATTACHED_DATABASE_NAME);
auto ret = store1->Attach(attachedConfig, attachedName, BUSY_TIMEOUT);
EXPECT_EQ(E_OK, ret.first);
EXPECT_EQ(1, ret.second);
QueryCheck1(store1);
// use the same attachedName to attach again
ret = store1->Attach(attachedConfig, attachedName, BUSY_TIMEOUT);
EXPECT_EQ(E_ATTACHED_DATABASE_EXIST, ret.first);
int ret = store1->Attach(alias, RdbAttachTest::ATTACHED_DATABASE_NAME, destEncryptKey);
EXPECT_EQ(E_NOT_SUPPORTED_ATTACH_IN_WAL_MODE, ret);
RdbHelper::DeleteRdbStore(RdbAttachTest::MAIN_DATABASE_NAME);
ret = store1->Detach(attachedName);
EXPECT_EQ(E_OK, ret.first);
EXPECT_EQ(0, ret.second);
QueryCheck2(store1);
}
// journal mode is TRUNCATE
// destEncryptKey is empty and isEncrypt_ is false
config.SetJournalMode(JournalMode::MODE_TRUNCATE);
std::shared_ptr<RdbStore> store2 = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(nullptr, store2);
/**
* @tc.name: RdbStore_Attach_004
* @tc.desc: Abnormal testCase for Attach with wrong path
* @tc.type: FUNC
*/
HWTEST_F(RdbAttachTest, RdbStore_Attach_004, TestSize.Level2)
{
const std::string attachedName = "attached";
RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
MainOpenCallback helper;
int errCode = E_OK;
// journal mode is wal
std::shared_ptr<RdbStore> store1 = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(nullptr, store1);
EXPECT_EQ(E_OK, errCode);
ret = store2->Attach(alias, RdbAttachTest::ATTACHED_DATABASE_NAME, destEncryptKey);
EXPECT_EQ(E_OK, ret);
RdbStoreConfig attachedConfig("/wrong/path");
auto ret = store1->Attach(attachedConfig, attachedName, BUSY_TIMEOUT);
EXPECT_EQ(E_INVALID_FILE_PATH, ret.first);
}
// destEncryptKey is not empty and isEncrypt_ is false
destEncryptKey = {1};
ret = store2->Attach(alias, RdbAttachTest::ATTACHED_DATABASE_NAME, destEncryptKey);
EXPECT_NE(E_OK, ret);
RdbHelper::DeleteRdbStore(RdbAttachTest::MAIN_DATABASE_NAME);
/**
* @tc.name: RdbStore_Attach_005
* @tc.desc: Abnormal testCase for Attach encrypted database
* @tc.type: FUNC
*/
HWTEST_F(RdbAttachTest, RdbStore_Attach_005, TestSize.Level2)
{
int errCode = E_OK;
AttachedOpenCallback attachedHelper;
RdbStoreConfig encryptAttachedConfig(RdbAttachTest::ENCRYPT_ATTACHED_DATABASE_NAME);
encryptAttachedConfig.SetEncryptStatus(true);
std::shared_ptr<RdbStore> encryptAttachedStore =
RdbHelper::GetRdbStore(encryptAttachedConfig, 1, attachedHelper, errCode);
EXPECT_NE(encryptAttachedStore, nullptr);
// destEncryptKey is not empty and isEncrypt_ is true
config.SetEncryptStatus(true);
std::shared_ptr<RdbStore> store3 = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(nullptr, store3);
encryptAttachedStore = nullptr;
const std::string attachedName = "attached";
RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
MainOpenCallback helper;
// journal mode is wal
std::shared_ptr<RdbStore> store1 = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(nullptr, store1);
EXPECT_EQ(E_OK, errCode);
ret = store3->Attach(alias, RdbAttachTest::ATTACHED_DATABASE_NAME, destEncryptKey);
EXPECT_NE(E_OK, ret);
auto ret = store1->Attach(encryptAttachedConfig, attachedName, BUSY_TIMEOUT);
EXPECT_EQ(E_OK, ret.first);
EXPECT_EQ(1, ret.second);
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("lisi"));
int res = store1->Insert(id, "test2", values);
EXPECT_EQ(res, E_OK);
EXPECT_EQ(id, 1);
QueryCheck1(store1);
ret = store1->Detach(attachedName);
EXPECT_EQ(E_OK, ret.first);
EXPECT_EQ(0, ret.second);
QueryCheck2(store1);
RdbHelper::DeleteRdbStore(RdbAttachTest::ENCRYPT_ATTACHED_DATABASE_NAME);
}
/**
* @tc.name: RdbStore_Attach_006
* @tc.desc: Abnormal testCase for Attach
* @tc.type: FUNC
*/
HWTEST_F(RdbAttachTest, RdbStore_Attach_006, TestSize.Level2)
{
const std::string attachedName = "attached";
RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
MainOpenCallback helper;
int errCode = E_OK;
// journal mode is wal
std::shared_ptr<RdbStore> store1 = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(nullptr, store1);
EXPECT_EQ(E_OK, errCode);
RdbStoreConfig attachedConfig(RdbAttachTest::ATTACHED_DATABASE_NAME);
auto ret = store1->Attach(attachedConfig, attachedName, BUSY_TIMEOUT);
EXPECT_EQ(E_OK, ret.first);
EXPECT_EQ(1, ret.second);
UpdateCheck(store1);
DeleteCheck(store1);
ret = store1->Detach(attachedName);
EXPECT_EQ(E_OK, ret.first);
EXPECT_EQ(0, ret.second);
}
void RdbAttachTest::QueryCheck1(std::shared_ptr<RdbStore> &store) const
@ -275,4 +341,88 @@ void RdbAttachTest::QueryCheck2(std::shared_ptr<RdbStore> &store) const
// detached, no table test2
resultSet = store->QuerySql("SELECT * FROM test2");
EXPECT_NE(resultSet, nullptr);
}
}
void RdbAttachTest::DeleteCheck(std::shared_ptr<RdbStore> &store) const
{
int changedRows = 0;
AbsRdbPredicates predicates("test1");
predicates.EqualTo("id", 1);
int ret = store->Delete(changedRows, predicates);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(changedRows, 1);
std::shared_ptr<ResultSet> resultSet =
store->QuerySql("SELECT * FROM test1 where name = 'lisi_update1'");
EXPECT_NE(resultSet, nullptr);
int count = 0;
resultSet->GetRowCount(count);
EXPECT_EQ(0, count);
int changedRows2 = 0;
AbsRdbPredicates predicates2("test2");
predicates2.EqualTo("id", 1);
ret = store->Delete(changedRows2, predicates2);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(changedRows2, 1);
std::shared_ptr<ResultSet> resultSet2 =
store->QuerySql("SELECT * FROM test2 where name = 'lisi_update2'");
EXPECT_NE(resultSet2, nullptr);
int count2 = 0;
resultSet2->GetRowCount(count2);
EXPECT_EQ(0, count2);
}
void RdbAttachTest::UpdateCheck(std::shared_ptr<RdbStore> &store) const
{
int changedRows = 0;
ValuesBucket values;
values.PutString("name", std::string("lisi_update1"));
AbsRdbPredicates predicates("test1");
predicates.EqualTo("id", 1);
int ret = store->Update(changedRows, values, predicates);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(changedRows, 1);
std::shared_ptr<ResultSet> resultSet =
store->QuerySql("SELECT * FROM test1 where name = 'lisi_update1'");
EXPECT_NE(resultSet, nullptr);
int count = 0;
resultSet->GetRowCount(count);
EXPECT_EQ(1, count);
values.Clear();
values.PutString("name", std::string("lisi_update2"));
AbsRdbPredicates predicates2("test2");
predicates2.EqualTo("id", 1);
int changedRows2 = 0;
ret = store->Update(changedRows2, values, predicates2);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(changedRows2, 1);
std::shared_ptr<ResultSet> resultSet2 =
store->QuerySql("SELECT * FROM test2 where name = 'lisi_update2'");
EXPECT_NE(resultSet2, nullptr);
int count2 = 0;
resultSet2->GetRowCount(count2);
EXPECT_EQ(1, count2);
}
void RdbAttachTest::InsertCheck(std::shared_ptr<RdbStore> &store) const
{
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
int ret = store->Insert(id, "test1", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(id, 1);
values.Clear();
values.PutInt("id", 1);
values.PutString("name", std::string("lisi"));
ret = store->Insert(id, "test2", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(id, 1);
}

View File

@ -205,7 +205,7 @@ HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_003, TestSize.Level1)
ConfigTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_EQ(store, nullptr);
EXPECT_EQ(errCode, E_EMPTY_FILE_NAME);
EXPECT_EQ(errCode, E_INVALID_FILE_PATH);
}
/**
@ -221,7 +221,7 @@ HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_004, TestSize.Level1)
ConfigTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_EQ(store, nullptr);
EXPECT_EQ(errCode, E_RELATIVE_PATH);
EXPECT_EQ(errCode, E_INVALID_FILE_PATH);
}
/**