update OpenHarmony 2.0 Canary

This commit is contained in:
mamingshuai 2021-06-02 00:44:57 +08:00
parent 38a3a878d5
commit 68cf4de24d
97 changed files with 15147 additions and 407 deletions

15
.gitattributes vendored Normal file
View File

@ -0,0 +1,15 @@
*.tgz filter=lfs diff=lfs merge=lfs -text
*.trp filter=lfs diff=lfs merge=lfs -text
*.apk filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.asm filter=lfs diff=lfs merge=lfs -text
*.8svn filter=lfs diff=lfs merge=lfs -text
*.9svn filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text
*.exe filter=lfs diff=lfs merge=lfs -text
*.a filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text

View File

@ -1,13 +0,0 @@
### 该问题是怎么引起的?
### 重现步骤
### 报错信息

View File

@ -1,14 +0,0 @@
### 相关的Issue
### 原因(目的、解决的问题等)
### 描述(做了什么,变更了什么)
### 测试用例(新增、改动、可能影响的功能)

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.idea/
*.iml
CMakeLists.txt
cmake-build-debug

View File

@ -1,3 +1,4 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

65
OAT.xml Normal file
View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2021 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.
Notes:
This is project config file for OpenHarmony OSS Audit Tool, if you have any questions or concerns, please email chenyaxun.
-->
<!-- OAT(OSS Audit Tool) configuration guide:
basedir: Root dir, the basedir + project path is the real source file location.
licensefile:
1.If the project don't have "LICENSE" in root dir, please define all the license files in this project in , OAT will check license files according to this rule.
tasklist(only for batch mode):
1. task: Define oat check thread, each task will start a new thread.
2. task name: Only an name, no practical effect.
3. task policy: Default policy for projects under this task, this field is required and the specified policy must defined in policylist.
4. task filter: Default filefilter for projects under this task, this field is required and the specified filefilter must defined in filefilterlist.
5. task project: Projects to be checked, the path field define the source root dir of the project.
policyList:
1. policy: All policyitems will be merged to default OAT.xml rules, the name of policy doesn't affect OAT check process.
2. policyitem: The fields type, name, path, desc is required, and the fields rule, group, filefilter is optional,the default value is:
<policyitem type="" name="" path="" desc="" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
3. policyitem type:
"compatibility" is used to check license compatibility in the specified path;
"license" is used to check source license header in the specified path;
"copyright" is used to check source copyright header in the specified path;
"import" is used to check source dependency in the specified path, such as import ... ,include ...
"filetype" is used to check file type in the specified path, supported file types: archive, binary
"filename" is used to check whether the specified file exists in the specified path(support projectroot in default OAT.xml), supported file names: LICENSE, README, README.OpenSource
4. policyitem name: This field is used for define the license, copyright, "*" means match all, the "!" prefix means could not match this value. For example, "!GPL" means can not use GPL license.
5. policyitem path: This field is used for define the source file scope to apply this policyitem, the "!" prefix means exclude the files. For example, "!.*/lib/.*" means files in lib dir will be exclude while process this policyitem.
6. policyitem rule and group: These two fields are used together to merge policy results. "may" policyitems in the same group means any one in this group passed, the result will be passed.
7. policyitem filefilter: Used to bind filefilter which define filter rules.
8. filefilter: Filter rules, the type filename is used to filter file name, the type filepath is used to filter file path.
Note:If the text contains special characters, please escape them according to the following rules:
" == &gt;
& == &gt;
' == &gt;
< == &gt;
> == &gt;
-->
<configuration>
<oatconfig>
<filefilterlist>
<filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies" >
<filteritem type="filepath" name=".*.db" desc="Database data file used for test case execution."/>
</filefilter>
</filefilterlist>
</oatconfig>
</configuration>

172
README.md
View File

@ -1,119 +1,107 @@
# distributeddatamgr_appdatamgr
# distributeddatamgr\_appdatamgr<a name="EN-US_TOPIC_0000001124534865"></a>
- [Introduction](#section11660541593)
- [Directory Structure](#section1464106163817)
- [Constraints](#section1718733212019)
- [Architecture](#section159991817144514)
- [Available APIs](#section11510542164514)
- [Usage Guidelines](#section1685211117463)
- [Repositories Involved](#section10365113863719)
- [RDB](#section1589234172717)
- [Preferences Database](#section1287582752719)
- [Directory Structure](#section161941989596)
- [Relational Database](#section101010894114)
- [Constraints](#section18387142613414)
- [Preferences Database](#section762641474720)
- [Constraints](#section1944481420489)
- [Repositories Involved](#section1371113476307)
## Introduction<a name="section11660541593"></a>
The distributed data management service allows you to manage data in a convenient, efficient, and secure way. It reduces development costs and creates a consistent and smooth user experience across devices.
> Currently, it supports storage of local lightweight key-value (KV) pairs. In the future, more data types will be supported.
Lightweight key-value pairs are structured and transaction-related (to be supported in the future). Dedicated APIs related to key-value pairs are provided.
The **relational database \(RDB\)** manages data based on relational models. With the underlying SQLite database, the OpenHarmony RDB provides a complete mechanism for managing local databases.
> Lightweight key-value (KV) data: The data is structured, the file is lightweight, and transactional (supported in the future), and a dedicated key-value pair interface is provided separately
The **preferences database** provides lightweight key-value operations for local applications to store a small amount of data. As the stored data is already loaded in the memory, the faster data access speed achieves a higher work efficiency. The preferences database is non-relational, and therefore it is not suitable for storing a large amount of data. Instead, the preferences database is usually used to operate data in key-value pairs.
![输入图片说明](https://images.gitee.com/uploads/images/2021/0422/200748_51a0cbd1_8046977.png "屏幕截图.png")
### RDB<a name="section1589234172717"></a>
The lightweight KV store is developed based on the KV storage capabilities provided by Utils, and provides key-value pair management capabilities for apps. On a platform with processes, the key-value pair management capabilities provided by the KV store can only be accessed by a specific process. On such a platform, the KV store is loaded in the app process as a basic library so that it cannot be accessed by other processes.
With the SQLite database as the persistence engine, the OpenHarmony RDB supports all features of the SQLite database , including but not limited to transactions, indices, views, triggers, foreign keys, parameterized queries, and prepared SQL statements.
The distributed data management service abstracts data operation APIs of different platforms into unified APIs for file operations. In this way, you do not need to pay attention to the file system differences between chip platforms.
**Figure 1** How RDB works<a name="fig3330103712254"></a>
![](figures/en-us_image_0000001115980740.png)
### Preferences Database<a name="section1287582752719"></a>
1. The preferences database provides operation classes for applications to operate the database.
2. With the **PreferencesHelper**, an app can load the content of a specified file to the **Preferences** instance. Each file has only one **Preferences** instance. The system stores the instance in the memory through a static container until the app removes the instance from the memory or deletes the file.
3. After obtaining the **Preferences** instance, the app can use the functions in **Preferences** to read data from or write data to the **Preferences** instance, and use **flush\(\)** or **flushSync\(\)** to save the modification to the file that stores the preference data.
**Figure 2** How the preferences database works<a name="fig833053712258"></a>
![](figures/en-us_image_0000001162419711.png)
## Directory Structure<a name="section161941989596"></a>
## Directory Structure<a name="section1464106163817"></a>
```
foundation/distributeddatamgr/appdatamgr/
└─appdatamgr_lite
│ BUILD.gn
├─dbm_kv_store
│ │ BUILD.gn
│ │
│ ├─inc
│ │ dbm_def.h
│ │
│ ├─innerkits
│ │ dbm_kv_store.h
│ │ dbm_kv_store_env.h
│ │
│ └─src
│ ├─kv_store_impl_hal
│ │ dbm_kv_store.c
│ │
│ └─kv_store_impl_posix
│ dbm_kv_store.c
└─include
dbm_config.h
dbm_errno.h
//foundation/distributeddatamgr/appdatamgr
├── frameworks # Framework code
│ └── innerkitsimpl # Internal API implementation
└── interfaces # APIs
└── innerkits # Internal APIs
```
## Constraints<a name="section1718733212019"></a>
### Lightweight Key-Value Pairs
-The platform should have file creation, reading, writing, deletion, modification, and locking capabilities. The semantic functions of APIs should be kept the same for different platforms (such as the LiteOS Cortex-M and LiteOS Cortex-A).
-Due to the differences in platform capabilities, the KV store capabilities need to be tailored accordingly. Internal implementation may be different for different platforms.
## Relational Database<a name="section101010894114"></a>
## Architecture<a name="section159991817144514"></a>
### Lightweight Key-Value Pairs
The KV store inherits capacities from Utils. In addition, the KV store provides data deletion and binary value reading and writing capabilities while ensuring the atomicity of operations. Capabilities specific to different platforms are abstracted separately and provided by each platform.
>- The mini system generally has poor performance and insufficient memory and computing capabilities. In data management scenarios, reading operations are much more than writing operations, and memory usage is sensitive.、
>- File operation APIs used by a platform are provided by the file system. These APIs are generallynot process-safe.
>- The mini system may have no lock capabilities or lock mechanism. In that case, concurrency is guaranteed by the service. If a lock mechanism is needed, a hook should be registered by the service.
Some basic concepts are as follows:
## Available APIs<a name="section11510542164514"></a>
- **Lightweight KV store**
- **Relational database \(RDB\)**
```
typedef struct DBM *KVStoreHandle;
// storeFullPath is a valid directory. The key-value pairs of the KV store will be stored in this directory.
// If you pass an empty string, key-value pairs of the KV store will be stored in the current directory.
int DBM_GetKVStore(const char* storeFullPath, KVStoreHandle* kvStore);
A database created on the basis of relational models. The RDB stores data in rows and columns.
int DBM_Get(KVStoreHandle db, const char* key, void* value, unsigned int count, unsigned int* realValueLen);
int DBM_Put(KVStoreHandle db, const char* key, void* value, unsigned int len);
int DBM_Delete(KVStoreHandle db, const char* key);
- **Result set**
int DBM_CloseKVStore(KVStoreHandle db);
// Ensure that all KVStore objects in the specified directory are closed before you delete the KV store.
int DBM_DeleteKVStore(const char* storeFullPath);
A set of query results used to access the data. You can access the required data in a result set in flexible modes.
## Usage Guidelines <a name="section1685211117463"></a>
- **Lightweight KV store**
- **SQLite database**
```
// Create or open the kvStore.
const char storeFullPath[] = ""; // A valid directory or an empty string
KVStoreHandle kvStore = NULL;
int ret = DBM_GetKVStore(storeFullPath, &kvStore);
A lightweight RDB in compliance with the atomicity, consistency, isolation, and durability \(ACID\) properties. It is an open-source database.
// Insert or update a key-value pair.
char key[] = "rw.sys.version";
struct {
int num;
char content[200];
} value;
memset_s(&value, sizeof(value), 0, sizeof(value));
value.num = 1;
strcpy_s(value.content, sizeof(value.content), "Hello world !");
ret = DBM_Put(kvStore, key, (void*)&value, sizeof(value));
// Read a key-value pair.
memset_s(&value, sizeof(value), 0, sizeof(value));
unsigned int realValLen = 0;
ret = DBM_Get(g_KVStoreHandle, key, &value, sizeof(value), &realValLen);
### Constraints<a name="section18387142613414"></a>
// Delete a key-value pair.
ret = DBM_Delete(kvStore, key);
The RDB can use a maximum of four connection pools to manage read and write operations.
// Close the KV store.
ret = DBM_CloseKVStore(kvStore);
To ensure data accuracy, the RDB supports only one writ operation at a time.
// Delete the KV store and remove all key-value pairs.
ret = DBM_DeleteKVStore(storeFullPath);
## Preferences Database<a name="section762641474720"></a>
```
Some basic concepts are as follows:
- **Key-value database**
A database that stores data in key-value pairs. The **key** indicates keyword, and **value** indicates the corresponding value.
- **Non-relational database**
A database not in compliance with the atomicity, consistency, isolation, and durability \(ACID\) database management properties of relational data transactions. Instead, the data in a non-relational database is independent and scalable.
- **Preference** **data**
A type of data that is frequently accessed and used.
### Constraints<a name="section1944481420489"></a>
A key should be a string with a maximum of 80 characters and cannot be an empty string.
A value in the format of string can have a maximum of 8192 characters. A value can be an empty string.
To avoid a high memory cost, it is recommended that the preferences database store no more than ten thousand data entries.
## Repositories Involved<a name="section1371113476307"></a>
Distributed Data Management subsystem
distributeddatamgr\_appdatamgr
third\_party\_sqlite
## Repositories Involved<a name="section10365113863719"></a>
distributeddatamgr_appdatamgr

View File

@ -1,120 +1,107 @@
# distributeddatamgr_appdatamgr
# 本地数据管理组件<a name="ZH-CN_TOPIC_0000001124534865"></a>
- [简介](#section11660541593)
- [目录](#section1464106163817)
- [约束](#section1718733212019)
- [软件架构](#section159991817144514)
- [接口](#section11510542164514)
- [使用](#section1685211117463)
- [涉及仓](#section10365113863719)
- [关系型数据库RDB](#section1589234172717)
- [轻量级偏好数据库Preferences](#section1287582752719)
- [目录](#section161941989596)
- [关系型数据库RDB](#section101010894114)
- [约束](#section18387142613414)
- [轻量级偏好数据库Preferences](#section762641474720)
- [约束](#section1944481420489)
- [相关仓](#section1371113476307)
## 简介<a name="section11660541593"></a>
数据管理服务为应用程序和用户提供更加便捷、高效和安全的数据管理能力。降低开发成本,打造应用跨设备运行一致、流畅的用户体验。
> 当前先支持轻量键值KV本地数据存储能力后续会逐步支持其他更丰富的数据类型。
>
> 轻量键值KV数据数据有结构文件轻量具有事务性未来支持单独提供一套专用的键值对接口
![输入图片说明](https://images.gitee.com/uploads/images/2021/0422/193406_a3e03a96_8046977.png "屏幕截图.png")
**关系型数据库Relational DatabaseRDB**是一种基于关系模型来管理数据的数据库。OpenHarmony关系型数据库基于SQLite组件提供了一套完整的对本地数据库进行管理的机制。
轻量级KV数据库依托当前公共基础库提供的KV存储能力开发为应用提供键值对参数管理能力。在有进程的平台上KV存储提供的参数管理供单进程访问不能被其他进程使用。在此类平台上KV存储作为基础库加载在应用进程以保障不被其他进程访问
**轻量级偏好数据库Preferences**主要提供轻量级Key-Value操作支持本地应用存储少量数据数据存储在本地文件中同时也加载在内存中的所以访问速度更快效率更高。轻量级偏好数据库属于非关系型数据库不宜存储大量数据经常用于操作键值对形式数据的场景。
分布式数据管理服务在不同平台上,将数据操作接口形成抽象层用来统一进行文件操作,使厂商不需要关注不同芯片平台文件系统的差异。
### 关系型数据库RDB<a name="section1589234172717"></a>
目前在轻量系统上默认关闭该特性需要使用时请用户修改vendor_hisilicon仓配置以开启。
OpenHarmony关系型数据库底层使用SQLite作为持久化存储引擎支持SQLite具有的所有数据库特性包括但不限于事务、索引、视图、触发器、外键、参数化查询和预编译SQL语句。
**图 1** 关系型数据库运作机制<a name="fig3330103712254"></a>
![](figures/zh-cn_image_0000001115980740.png)
### 轻量级偏好数据库Preferences<a name="section1287582752719"></a>
1. 本模块提供偏好型数据库的操作类,应用通过这些操作类完成数据库操作。
2. 借助PreferencesHelper可以将指定文件的内容加载到Preferences实例每个文件最多有一个Preferences实例系统会通过静态容器将该实例存储在内存中直到主动从内存中移除该实例或者删除该文件。
3. 获取Preferences实例后可以借助Preferences类的函数从Preferences实例中读取数据或者将数据写入Preferences实例通过flush或者flushSync将Preferences实例持久化。
**图 2** 轻量级偏好数据库运行机制<a name="fig833053712258"></a>
![](figures/zh-cn_image_0000001162419711.png)
## 目录<a name="section161941989596"></a>
## 目录<a name="section1464106163817"></a>
```
foundation/distributeddatamgr/appdatamgr/
└─appdatamgr_lite
│ BUILD.gn
├─dbm_kv_store
│ │ BUILD.gn
│ │
│ ├─inc
│ │ dbm_def.h
│ │
│ ├─innerkits
│ │ dbm_kv_store.h
│ │ dbm_kv_store_env.h
│ │
│ └─src
│ ├─kv_store_impl_hal
│ │ dbm_kv_store.c
│ │
│ └─kv_store_impl_posix
│ dbm_kv_store.c
└─include
dbm_config.h
dbm_errno.h
//foundation/distributeddatamgr/appdatamgr
├── frameworks # 框架层代码
│ └── innerkitsimpl # 内部接口实现
└── interfaces # 接口代码
└── innerkits # 内部接口声明
```
## 约束<a name="section1718733212019"></a>
### 轻量键值KV数据
- 依赖平台具有正常的文件创建、读写删除修改、锁等能力针对不同平台如LiteOS-M内核、LiteOS-A内核等尽可能表现接口语义功能的不变
- 由于平台能力差异数据库能力需要做相应裁剪,其中不同平台内部实现可能不同
- 对于指定路径仅支持创建数据库单例,不支持同一路径创建多数据库实例对象
## 软件架构<a name="section159991817144514"></a>
### 轻量键值KV数据
KV存储能力继承自公共基础库原始设计在原有能力基础上进行增强新增提供数据删除及二进制value读写能力的同时保证操作的原子性为区别平台差异将依赖平台差异的内容单独抽象由对应产品平台提供。
>- 轻量系统普遍性能有限,内存及计算能力不足,对于数据管理的场景大多读多写少,且内存占用敏感;
>- 平台使用的文件操作接口是由文件系统提供,一般来说文件操作接口本身并不是进程安全的,请格外注意;
>- 轻量系统存在不具备锁能力的情况不提供锁的机制并发由业务保证若需要提供有锁机制则需要提供hook由业务进行注册。
## 关系型数据库RDB<a name="section101010894114"></a>
## 接口<a name="section11510542164514"></a>
- **轻量KV存储**
以下是几个基本概念:
```
typedef struct DBM *KVStoreHandle;
// storeFullPath为合法目录创建的KV将已此目录创建条目
// 传入空串则以当前目录创建
int DBM_GetKVStore(const char* storeFullPath, KVStoreHandle* kvStore);
- **关系型数据库**
int DBM_Get(KVStoreHandle db, const char* key, void* value, unsigned int count, unsigned int* realValueLen);
int DBM_Put(KVStoreHandle db, const char* key, void* value, unsigned int len);
int DBM_Delete(KVStoreHandle db, const char* key);
创建在关系模型基础上的数据库,以行和列的形式存储数据。
int DBM_CloseKVStore(KVStoreHandle db);
// 请确保删除数据库前已关闭该目录对应的所有数据库对象
int DBM_DeleteKVStore(const char* storeFullPath);
```
## 使用<a name="section1685211117463"></a>
- **结果集**
- **轻量KV存储**
指用户查询之后的结果集合,可以对数据进行访问。结果集提供了灵活的数据访问方式,可以更方便的拿到用户想要的数据。
```
// 创建或打开数据库
const char storeFullPath[] = ""; // 目录或空字符串
KVStoreHandle kvStore = NULL;
int ret = DBM_GetKVStore(storeFullPath, &kvStore);
- **SQLite数据库**
// 插入或修改数据
char key[] = "rw.sys.version";
struct {
int num;
char content[200];
} value;
memset_s(&value, sizeof(value), 0, sizeof(value));
value.num = 1;
strcpy_s(value.content, sizeof(value.content), "Hello world !");
ret = DBM_Put(kvStore, key, (void*)&value, sizeof(value));
一款轻量级的数据库是遵守ACID的关系型数据库组件。它是一个开源的项目。
// 读取数据
memset_s(&value, sizeof(value), 0, sizeof(value));
unsigned int realValLen = 0;
ret = DBM_Get(g_KVStoreHandle, key, &value, sizeof(value), &realValLen);
// 删除数据
ret = DBM_Delete(kvStore, key);
### 约束<a name="section18387142613414"></a>
// 关闭数据库
ret = DBM_CloseKVStore(kvStore);
数据库中连接池的最大数量是4个用以管理用户的读写操作。
// 删除数据库
ret = DBM_DeleteKVStore(storeFullPath);
为保证数据的准确性,数据库同一时间只能支持一个写操作。
```
## 轻量级偏好数据库Preferences<a name="section762641474720"></a>
以下是几个基本概念:
- **Key-Value数据库**
一种以键值对存储数据的一种数据库。Key是关键字Value是值。
- **非关系型数据库**
区别于关系数据库不保证遵循ACIDAtomic、Consistency、Isolation及Durability特性不采用关系模型来组织数据数据之间无关系扩展性好。
- **偏好数据**
用户经常访问和使用的数据。
### 约束<a name="section1944481420489"></a>
Key键为String类型要求非空且长度不超过80个字符。
如果Value值为String类型可以为空但是长度不超过8192个字符。
存储的数据量应该是轻量级的,建议存储的数据不超过一万条,否则会在内存方面产生较大的开销。
## 相关仓<a name="section1371113476307"></a>
分布式数据管理子系统
distributeddatamgr\_appdatamgr
third\_party\_sqlite
## 涉及仓<a name="section10365113863719"></a>
distributeddatamgr_appdatamgr

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

37
find_java_files.py Executable file
View File

@ -0,0 +1,37 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2021 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 os
import sys
import fnmatch
def FindInDirectory(directory, filename_filter):
for root, _dirnames, filenames in os.walk(directory):
matched_files = fnmatch.filter(filenames, filename_filter)
for file in matched_files:
print(os.path.join(root, file))
def main(args):
dirs = args
for directory in dirs:
if os.path.isdir(directory):
FindInDirectory(directory, "*.java")
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_PREFERENCES_LOGGER_H
#define NATIVE_PREFERENCES_LOGGER_H
#include "hilog/log.h"
namespace OHOS {
namespace NativePreferences {
static const OHOS::HiviewDFX::HiLogLabel DFS_LABEL = { LOG_CORE, 0xD001650, "NativePreferences" };
#define LOG_DEBUG(...) ((void)OHOS::HiviewDFX::HiLog::Debug(DFS_LABEL, __VA_ARGS__))
#define LOG_INFO(...) ((void)OHOS::HiviewDFX::HiLog::Info(DFS_LABEL, __VA_ARGS__))
#define LOG_WARN(...) ((void)OHOS::HiviewDFX::HiLog::Warn(DFS_LABEL, __VA_ARGS__))
#define LOG_ERROR(...) ((void)OHOS::HiviewDFX::HiLog::Error(DFS_LABEL, __VA_ARGS__))
#define LOG_FATAL(...) ((void)OHOS::HiviewDFX::HiLog::Fatal(DFS_LABEL, __VA_ARGS__))
} // namespace NativePreferences
} // namespace OHOS
#endif // NATIVE_PREFERENCES_LOGGER_H

View File

@ -0,0 +1,142 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_IMPL_H
#define PREFERENCES_IMPL_H
#include <any>
#include <condition_variable>
#include <filesystem>
#include <list>
#include <map>
#include <mutex>
#include <string>
#include <vector>
#include "preferences.h"
#include "preferences_observer.h"
#include "preferences_value.h"
#include "task_pool.h"
namespace OHOS {
namespace NativePreferences {
class PreferencesImpl : public Preferences {
public:
PreferencesImpl(const std::filesystem::path &path);
virtual ~PreferencesImpl();
int Init();
virtual int GetInt(const std::string &key, int defValue) override;
virtual std::string GetString(const std::string &key, const std::string &defValue) override;
virtual bool GetBool(const std::string &key, bool defValue) override;
virtual float GetFloat(const std::string &key, float defValue) override;
virtual int64_t GetLong(const std::string &key, int64_t defValue) override;
virtual bool HasKey(const std::string &key) override;
virtual int PutInt(const std::string &key, int value) override;
virtual int PutString(const std::string &key, const std::string &value) override;
virtual int PutBool(const std::string &key, bool value) override;
virtual int PutLong(const std::string &key, int64_t value) override;
virtual int PutFloat(const std::string &key, float value) override;
virtual int Delete(const std::string &key) override;
virtual int Clear() override;
virtual void Flush() override;
virtual int FlushSync() override;
virtual void RegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver) override;
virtual void UnRegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver) override;
static std::filesystem::path MakeBackupPath(const std::filesystem::path &prefPath);
static std::filesystem::path MakeBrokenPath(const std::filesystem::path &prefPath);
private:
class MemoryToDiskRequest {
public:
MemoryToDiskRequest(const std::map<std::string, PreferencesValue> &writeToDiskMap,
const std::list<std::string> &keysModified,
const std::vector<std::weak_ptr<PreferencesObserver>> preferencesObservers, int64_t memStataGeneration);
~MemoryToDiskRequest(){};
void SetDiskWriteResult(bool wasWritten, int result);
bool isSyncRequest_;
int64_t memoryStateGeneration_;
std::map<std::string, PreferencesValue> writeToDiskMap_;
std::mutex reqMutex_;
std::condition_variable reqCond_;
std::list<std::string> keysModified_;
std::vector<std::weak_ptr<PreferencesObserver>> preferencesObservers_;
int writeToDiskResult_;
bool wasWritten_;
bool handled_;
};
std::shared_ptr<MemoryToDiskRequest> commitToMemory();
void notifyPreferencesObserver(const MemoryToDiskRequest &request);
void PutPreferencesValue(const std::string &key, const PreferencesValue &value);
void StartLoadFromDisk();
int CheckKey(const std::string &key);
/* thread function */
static void LoadFromDisk(PreferencesImpl &pref);
void AwaitLoadFile();
void WriteToDiskFile(std::shared_ptr<MemoryToDiskRequest> mcr);
bool CheckRequestValidForStateGeneration(const MemoryToDiskRequest &mcr);
bool ReadSettingXml(const std::filesystem::path &prefPath, std::map<std::string, PreferencesValue> &prefMap);
bool WriteSettingXml(const std::filesystem::path &prefPath, const std::map<std::string, PreferencesValue> &prefMap);
bool loaded_;
/* Current memory state (always increasing) */
int64_t currentMemoryStateGeneration_;
/* Latest memory state that was committed to disk */
int64_t diskStateGeneration_;
std::mutex mutex_;
std::condition_variable cond_;
std::vector<std::weak_ptr<PreferencesObserver>> preferencesObservers_;
std::map<std::string, PreferencesValue> map_;
std::list<std::string> modifiedKeys_;
const std::filesystem::path filePath_;
const std::filesystem::path backupPath_;
const std::filesystem::path brokenPath_;
// Task pool
/* max threads of the task pool. */
static constexpr int MAX_TP_THREADS = 10;
/* min threads of the task pool. */
static constexpr int MIN_TP_THREADS = 1;
TaskPool taskPool_;
};
} // End of namespace NativePreferences
} // End of namespace OHOS
#endif // End of #ifndef PREFERENCES_IMPL_H

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_VALUE_H
#define PREFERENCES_VALUE_H
#include <string>
#include <variant>
namespace OHOS {
namespace NativePreferences {
class PreferencesValue {
public:
~PreferencesValue(){};
explicit PreferencesValue(int value);
explicit PreferencesValue(int64_t value);
explicit PreferencesValue(float value);
explicit PreferencesValue(bool value);
explicit PreferencesValue(std::string value);
bool IsInt() const;
bool IsLong() const;
bool IsFloat() const;
bool IsBool() const;
bool IsString() const;
operator int();
operator float();
operator bool();
operator int64_t();
operator std::string();
bool operator==(const PreferencesValue &value);
private:
std::variant<int, int64_t, float, bool, std::string> data_;
};
} // End of namespace NativePreferences
} // End of namespace OHOS
#endif // End of #ifndef PREFERENCES_VALUE_H

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_XML_UTILS_H
#define PREFERENCES_XML_UTILS_H
#include <string>
#include <vector>
namespace OHOS {
namespace NativePreferences {
class Element {
public:
std::string tag_;
std::string key_;
std::string value_;
std::vector<Element> children_;
};
class PreferencesXmlUtils {
public:
static bool ReadSettingXml(const std::string &fileName, std::vector<Element> &settings);
static bool WriteSettingXml(const std::string &fileName, std::vector<Element> &settings);
static void LimitXmlPermission(const std::string &fileName);
static void XmlInitParser();
static void XmlCleanupParser();
private:
PreferencesXmlUtils()
{
}
~PreferencesXmlUtils()
{
}
};
} // End of namespace NativePreferences
} // End of namespace OHOS
#endif // End of #ifndef PREFERENCES_XML_UTILS_H

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef TASK_POOL_H
#define TASK_POOL_H
#include <condition_variable>
#include <functional>
#include <map>
#include <mutex>
#include <string>
#include <thread>
#include "task_queue.h"
namespace OHOS {
namespace NativePreferences {
class TaskPool {
public:
// maxThreads > 0.
TaskPool(int maxThreads, int minThreads);
// Start the task pool.
int Start();
// Stop the task pool.
void Stop();
// Schedule a task, the task can be ran in any thread.
int Schedule(const Task &task);
// Schedule tasks one by one.
int Schedule(const std::string &queueTag, const Task &task);
// Shrink memory associated with the given tag if possible.
void ShrinkMemory(const std::string &tag);
// Status report.
void Report();
~TaskPool();
private:
int SpawnThreads(bool isStart);
bool IdleExit(std::unique_lock<std::mutex> &lock);
void SetThreadFree();
Task ReapTask(TaskQueue *&queue);
int GetTask(Task &task, TaskQueue *&queue);
bool IsGenericWorker() const;
void BecomeGenericWorker();
void ExitGenericWorker();
void TaskWorker();
void FinishExecuteTask(TaskQueue *taskQueue);
void TryToSpawnThreads();
// Member Variables
static constexpr int IDLE_WAIT_PERIOD = 1; // wait 1 second before exiting.
std::mutex tasksMutex_;
std::condition_variable hasTasks_;
std::map<std::string, TaskQueue> queuedTasks_;
TaskQueue genericTasks_;
std::thread::id genericThread_; // execute generic task only.
int genericTaskCount_;
int queuedTaskCount_;
bool isStarted_;
bool isStopping_; // Stop() invoked.
bool isGenericThreadIdle_;
std::condition_variable allThreadsExited_;
// Thread counter.
int maxThreads_;
int minThreads_;
int curThreads_;
int idleThreads_;
};
} // namespace NativePreferences
} // namespace OHOS
#endif // TASK_POOL_H

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef TASK_QUEUE_H
#define TASK_QUEUE_H
#include <queue>
#include <thread>
namespace OHOS {
namespace NativePreferences {
using Task = std::function<void(void)>;
class TaskQueue {
public:
explicit TaskQueue(bool lockable = true);
~TaskQueue();
void PutTask(const Task &task);
Task GetTaskAutoLock();
void ReleaseLock();
bool IsEmptyAndUnlocked();
private:
bool lockable_;
std::thread::id lockThread_;
std::queue<Task> tasks_;
};
} // namespace NativePreferences
} // namespace OHOS
#endif // TASK_QUEUE_H

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2021 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 "preferences_helper.h"
#include <limits.h>
#include <stdlib.h>
#include <cerrno>
#include <utility>
#include "logger.h"
#include "preferences.h"
#include "preferences_errno.h"
#include "preferences_impl.h"
namespace OHOS {
namespace NativePreferences {
std::map<std::string, std::shared_ptr<Preferences>> PreferencesHelper::prefsCache_;
std::mutex PreferencesHelper::prefsCacheMutex_;
static bool IsFileExist(const std::filesystem::path &path)
{
FILE *file = std::fopen(path.c_str(), "r");
if (file != nullptr) {
std::fclose(file);
return true;
}
return false;
}
std::string PreferencesHelper::GetRealPath(const std::string &path, int &errorCode)
{
if (path.empty()) {
LOG_ERROR("The path can not be empty.");
errorCode = E_EMPTY_FILE_PATH;
return "";
}
if (path.front() != '/') {
LOG_ERROR("The path can not be relative path.");
errorCode = E_RELATIVE_PATH;
return "";
}
if (strlen(path.c_str()) > PATH_MAX) {
LOG_ERROR("The path exceeds max length.");
errorCode = E_PATH_EXCEED_MAX_LENGTH;
return "";
}
std::string::size_type pos = path.find_last_of('/');
if (pos == std::string::npos) {
LOG_ERROR("path can not be relative path.");
errorCode = E_RELATIVE_PATH;
return "";
}
std::string filePath = path.substr(0, pos);
char canonicalPath[PATH_MAX + 1] = { 0 };
if (realpath(filePath.c_str(), canonicalPath) == NULL) {
LOG_ERROR("Failed to obtain real path, errno:%{public}d", errno);
errorCode = E_INVALID_FILE_PATH;
return "";
}
std::string fileName = path.substr(pos + 1, path.length());
if (fileName.empty()) {
LOG_ERROR("file name can not be empty.");
errorCode = E_EMPTY_FILE_NAME;
return "";
}
errorCode = E_OK;
std::string realFilePath(canonicalPath);
return realFilePath.append("/").append(fileName);
}
std::shared_ptr<Preferences> PreferencesHelper::GetPreferences(const std::string &path, int &errCode)
{
std::string realPath = GetRealPath(path, errCode);
if (realPath == "" || errCode != E_OK) {
return nullptr;
}
std::lock_guard<std::mutex> lock(prefsCacheMutex_);
std::map<std::string, std::shared_ptr<Preferences>>::iterator it = prefsCache_.find(realPath);
if (it != prefsCache_.end()) {
return it->second;
}
std::filesystem::path filePath = realPath.c_str();
std::shared_ptr<PreferencesImpl> pref = std::make_shared<PreferencesImpl>(filePath);
errCode = pref->Init();
if (errCode != E_OK) {
return nullptr;
}
prefsCache_.insert(make_pair(realPath, pref));
return pref;
}
int PreferencesHelper::DeletePreferences(const std::string &path)
{
int errCode = E_OK;
std::string realPath = GetRealPath(path, errCode);
if (realPath == "" || errCode != E_OK) {
return errCode;
}
std::lock_guard<std::mutex> lock(prefsCacheMutex_);
std::map<std::string, std::shared_ptr<Preferences>>::iterator it = prefsCache_.find(realPath);
if (it != prefsCache_.end()) {
prefsCache_.erase(it);
}
std::filesystem::path filePath = realPath.c_str();
std::filesystem::path backupPath = PreferencesImpl::MakeBackupPath(filePath);
std::filesystem::path brokenPath = PreferencesImpl::MakeBrokenPath(filePath);
std::remove(filePath.c_str());
std::remove(backupPath.c_str());
std::remove(brokenPath.c_str());
if (IsFileExist(filePath) || IsFileExist(backupPath) || IsFileExist(brokenPath)) {
return E_DELETE_FILE_FAIL;
}
return E_OK;
}
int PreferencesHelper::RemovePreferencesFromCache(const std::string &path)
{
int errCode = E_OK;
std::string realPath = GetRealPath(path, errCode);
if (realPath == "" || errCode != E_OK) {
return errCode;
}
std::lock_guard<std::mutex> lock(prefsCacheMutex_);
std::map<std::string, std::shared_ptr<Preferences>>::iterator it = prefsCache_.find(realPath);
if (it == prefsCache_.end()) {
return E_OK;
}
prefsCache_.erase(it);
return E_OK;
}
} // End of namespace NativePreferences
} // End of namespace OHOS

View File

@ -0,0 +1,588 @@
/*
* Copyright (c) 2021 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 "preferences_impl.h"
#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
#include <functional>
#include "logger.h"
#include "preferences_errno.h"
#include "preferences_xml_utils.h"
namespace OHOS {
namespace NativePreferences {
static bool IsFileExist(const std::filesystem::path &inputPath)
{
char path[PATH_MAX + 1] = { 0x00 };
if (strlen(inputPath.c_str()) > PATH_MAX || realpath(inputPath.c_str(), path) == NULL) {
return false;
}
const char *pathString = path;
FILE *file = std::fopen(pathString, "r");
if (file != nullptr) {
std::fclose(file);
return true;
}
return false;
}
PreferencesImpl::PreferencesImpl(const std::filesystem::path &filePath)
: loaded_(false), filePath_(filePath), backupPath_(MakeBackupPath(filePath_)),
brokenPath_(MakeBrokenPath(filePath_)), taskPool_(TaskPool(MAX_TP_THREADS, MIN_TP_THREADS))
{
currentMemoryStateGeneration_ = 0;
diskStateGeneration_ = 0;
}
std::filesystem::path PreferencesImpl::MakeBackupPath(const std::filesystem::path &prefPath)
{
std::filesystem::path backupPath = prefPath;
backupPath += ".bak";
return backupPath;
}
std::filesystem::path PreferencesImpl::MakeBrokenPath(const std::filesystem::path &prefPath)
{
std::filesystem::path brokenPath = prefPath;
brokenPath += ".bak";
return brokenPath;
}
PreferencesImpl::~PreferencesImpl()
{
taskPool_.Stop();
}
int PreferencesImpl::Init()
{
int errCode = taskPool_.Start();
if (errCode != E_OK) {
return errCode;
}
StartLoadFromDisk();
return E_OK;
}
void PreferencesImpl::StartLoadFromDisk()
{
{
std::lock_guard<std::mutex> lock(mutex_);
loaded_ = false;
}
taskPool_.Schedule(std::string("PreferencesImpl"), std::bind(&PreferencesImpl::LoadFromDisk, std::ref(*this)));
}
int PreferencesImpl::CheckKey(const std::string &key)
{
if (key.empty()) {
return E_KEY_EMPTY;
}
if (Preferences::MAX_KEY_LENGTH < key.length()) {
return E_KEY_EXCEED_MAX_LENGTH;
}
return E_OK;
}
/* static */
void PreferencesImpl::LoadFromDisk(PreferencesImpl &pref)
{
std::lock_guard<std::mutex> lock(pref.mutex_);
if (pref.loaded_) {
return;
}
if (IsFileExist(pref.backupPath_)) {
if (std::remove(pref.filePath_.c_str())) {
LOG_ERROR("Couldn't delete file %{private}s when LoadFromDisk and backup exist.", pref.filePath_.c_str());
}
if (std::rename(pref.backupPath_.c_str(), pref.filePath_.c_str())) {
LOG_ERROR("Couldn't rename backup file %{private}s to file %{private}s,when LoadFromDisk and backup "
"exist.",
pref.backupPath_.c_str(), pref.filePath_.c_str());
} else {
PreferencesXmlUtils::LimitXmlPermission(pref.filePath_);
}
}
if (IsFileExist(pref.filePath_)) {
pref.ReadSettingXml(pref.filePath_, pref.map_);
}
pref.loaded_ = true;
pref.cond_.notify_all();
}
void PreferencesImpl::AwaitLoadFile()
{
std::unique_lock<std::mutex> lock(mutex_);
if (!loaded_) {
cond_.wait(lock, [this] { return loaded_; });
}
}
void PreferencesImpl::WriteToDiskFile(std::shared_ptr<MemoryToDiskRequest> mcr)
{
bool fileExists = false;
if (IsFileExist(filePath_)) {
fileExists = true;
}
if (fileExists) {
bool needWrite = CheckRequestValidForStateGeneration(*mcr);
if (!needWrite) {
mcr->SetDiskWriteResult(false, E_OK);
return;
}
if (IsFileExist(backupPath_)) {
if (std::remove(filePath_.c_str())) {
LOG_ERROR("Couldn't delete file %{private}s when writeToFile and backup exist.", filePath_.c_str());
}
} else {
if (std::rename(filePath_.c_str(), backupPath_.c_str())) {
LOG_ERROR("Couldn't rename file %{private}s to backup file %{private}s", filePath_.c_str(),
backupPath_.c_str());
mcr->SetDiskWriteResult(false, E_ERROR);
return;
} else {
PreferencesXmlUtils::LimitXmlPermission(backupPath_);
}
}
}
if (WriteSettingXml(filePath_, mcr->writeToDiskMap_)) {
if (std::remove(backupPath_.c_str())) {
LOG_ERROR("Couldn't delete backup file %{private}s when writeToFile finish.", backupPath_.c_str());
}
diskStateGeneration_ = mcr->memoryStateGeneration_;
mcr->SetDiskWriteResult(true, E_OK);
} else {
/* Clean up an unsuccessfully written file */
if (IsFileExist(filePath_)) {
if (std::remove(filePath_.c_str())) {
LOG_ERROR("Couldn't clean up partially-written file %{private}s", filePath_.c_str());
}
}
mcr->SetDiskWriteResult(false, E_ERROR);
}
}
bool PreferencesImpl::CheckRequestValidForStateGeneration(const MemoryToDiskRequest &mcr)
{
bool valid = false;
if (diskStateGeneration_ < mcr.memoryStateGeneration_) {
if (mcr.isSyncRequest_) {
valid = true;
} else {
if (currentMemoryStateGeneration_ == mcr.memoryStateGeneration_) {
valid = true;
}
}
}
return valid;
}
int PreferencesImpl::GetInt(const std::string &key, int defValue)
{
if (CheckKey(key) != E_OK) {
return defValue;
}
AwaitLoadFile();
std::lock_guard<std::mutex> lock(mutex_);
int ret = defValue;
auto iter = map_.find(key);
if (iter != map_.end()) {
PreferencesValue val = iter->second;
if (val.IsInt()) {
ret = val;
}
}
return ret;
}
std::string PreferencesImpl::GetString(const std::string &key, const std::string &defValue)
{
if (CheckKey(key) != E_OK) {
return defValue;
}
AwaitLoadFile();
std::lock_guard<std::mutex> lock(mutex_);
std::string ret = defValue;
auto iter = map_.find(key);
if (iter != map_.end()) {
PreferencesValue val = iter->second;
if (val.IsString()) {
ret = (std::string)val;
}
}
return ret;
}
bool PreferencesImpl::GetBool(const std::string &key, bool defValue)
{
if (CheckKey(key) != E_OK) {
return defValue;
}
AwaitLoadFile();
std::lock_guard<std::mutex> lock(mutex_);
bool ret = defValue;
auto iter = map_.find(key);
if (iter != map_.end()) {
PreferencesValue val = iter->second;
if (val.IsBool()) {
ret = val;
}
}
return ret;
}
float PreferencesImpl::GetFloat(const std::string &key, float defValue)
{
if (CheckKey(key) != E_OK) {
return defValue;
}
AwaitLoadFile();
std::lock_guard<std::mutex> lock(mutex_);
float ret = defValue;
auto iter = map_.find(key);
if (iter != map_.end()) {
PreferencesValue val = iter->second;
if (val.IsFloat()) {
ret = val;
}
}
return ret;
}
int64_t PreferencesImpl::GetLong(const std::string &key, int64_t defValue)
{
if (CheckKey(key) != E_OK) {
return defValue;
}
AwaitLoadFile();
std::lock_guard<std::mutex> lock(mutex_);
int64_t ret = defValue;
auto iter = map_.find(key);
if (iter != map_.end()) {
PreferencesValue val = iter->second;
if (val.IsLong()) {
ret = val;
}
}
return ret;
}
bool PreferencesImpl::ReadSettingXml(
const std::filesystem::path &prefPath, std::map<std::string, PreferencesValue> &prefMap)
{
std::vector<Element> settings;
if (!PreferencesXmlUtils::ReadSettingXml(prefPath.generic_string(), settings)) {
LOG_ERROR("ReadSettingXml:%{private}s failed!", filePath_.c_str());
return false;
}
for (auto it = settings.begin(); it != settings.end(); it++) {
Element element = *it;
if (element.tag_.compare("int") == 0) {
int value = atoi(element.value_.c_str());
prefMap.insert(std::make_pair(element.key_, PreferencesValue(value)));
} else if (element.tag_.compare("bool") == 0) {
bool value = (element.value_.compare("true") == 0) ? true : false;
prefMap.insert(std::make_pair(element.key_, PreferencesValue(value)));
} else if (element.tag_.compare("long") == 0) {
int64_t value = static_cast<int64_t>(atoll(element.value_.c_str()));
prefMap.insert(std::make_pair(element.key_, PreferencesValue(value)));
} else if (element.tag_.compare("float") == 0) {
float value = atof(element.value_.c_str());
prefMap.insert(std::make_pair(element.key_, PreferencesValue(value)));
} else if (element.tag_.compare("string") == 0) {
prefMap.insert(std::make_pair(element.key_, PreferencesValue(element.value_)));
} else {
LOG_WARN(
"ReadSettingXml:%{private}s, unknown element tag:%{public}s.", prefPath.c_str(), element.tag_.c_str());
}
}
return true;
}
bool PreferencesImpl::WriteSettingXml(
const std::filesystem::path &prefPath, const std::map<std::string, PreferencesValue> &prefMap)
{
std::vector<Element> settings;
for (auto it = prefMap.begin(); it != prefMap.end(); it++) {
Element elem;
elem.key_ = it->first;
PreferencesValue value = it->second;
if (value.IsInt()) {
elem.tag_ = std::string("int");
elem.value_ = std::to_string((int)value);
} else if (value.IsBool()) {
elem.tag_ = std::string("bool");
elem.value_ = std::to_string((bool)value);
} else if (value.IsLong()) {
elem.tag_ = std::string("long");
elem.value_ = std::to_string((int64_t)value);
} else if (value.IsFloat()) {
elem.tag_ = std::string("float");
elem.value_ = std::to_string((float)value);
} else if (value.IsString()) {
elem.tag_ = std::string("string");
elem.value_ = (std::string)value;
} else {
LOG_WARN("WriteSettingXml:%{private}s, unknown element type.", filePath_.c_str());
continue;
}
settings.push_back(elem);
}
return PreferencesXmlUtils::WriteSettingXml(prefPath.generic_string(), settings);
}
bool PreferencesImpl::HasKey(const std::string &key)
{
if (CheckKey(key) != E_OK) {
return false;
}
AwaitLoadFile();
std::lock_guard<std::mutex> lock(mutex_);
return (map_.find(key) != map_.end());
}
void PreferencesImpl::RegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver)
{
std::lock_guard<std::mutex> lock(mutex_);
std::weak_ptr<PreferencesObserver> weakPreferencesObserver = preferencesObserver;
preferencesObservers_.push_back(weakPreferencesObserver);
}
void PreferencesImpl::UnRegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver)
{
std::lock_guard<std::mutex> lock(mutex_);
for (auto it = preferencesObservers_.begin(); it != preferencesObservers_.end(); ++it) {
std::weak_ptr<PreferencesObserver> weakPreferencesObserver = *it;
std::shared_ptr<PreferencesObserver> sharedPreferencesObserver = weakPreferencesObserver.lock();
if (!sharedPreferencesObserver || sharedPreferencesObserver == preferencesObserver) {
preferencesObservers_.erase(it);
break;
}
}
}
void PreferencesImpl::PutPreferencesValue(const std::string &key, const PreferencesValue &value)
{
AwaitLoadFile();
std::lock_guard<std::mutex> lock(mutex_);
auto iter = map_.find(key);
if (iter != map_.end()) {
PreferencesValue &val = iter->second;
if (val == value) {
return;
}
}
map_.insert_or_assign(key, value);
modifiedKeys_.push_back(key);
}
int PreferencesImpl::PutInt(const std::string &key, int value)
{
int errCode = CheckKey(key);
if (errCode != E_OK) {
return errCode;
}
PutPreferencesValue(key, PreferencesValue(value));
return E_OK;
}
int PreferencesImpl::PutString(const std::string &key, const std::string &value)
{
int errCode = CheckKey(key);
if (errCode != E_OK) {
return errCode;
}
PutPreferencesValue(key, PreferencesValue(value));
return E_OK;
}
int PreferencesImpl::PutBool(const std::string &key, bool value)
{
int errCode = CheckKey(key);
if (errCode != E_OK) {
return errCode;
}
PutPreferencesValue(key, PreferencesValue(value));
return E_OK;
}
int PreferencesImpl::PutLong(const std::string &key, int64_t value)
{
int errCode = CheckKey(key);
if (errCode != E_OK) {
return errCode;
}
PutPreferencesValue(key, PreferencesValue(value));
return E_OK;
}
int PreferencesImpl::PutFloat(const std::string &key, float value)
{
int errCode = CheckKey(key);
if (errCode != E_OK) {
return errCode;
}
PutPreferencesValue(key, PreferencesValue(value));
return E_OK;
}
int PreferencesImpl::Delete(const std::string &key)
{
int errCode = CheckKey(key);
if (errCode != E_OK) {
return errCode;
}
std::lock_guard<std::mutex> lock(mutex_);
auto pos = map_.find(key);
if (pos != map_.end()) {
map_.erase(pos);
modifiedKeys_.push_back(key);
}
return E_OK;
}
int PreferencesImpl::Clear()
{
std::lock_guard<std::mutex> lock(mutex_);
if (!map_.empty()) {
for (auto &kv : map_) {
modifiedKeys_.push_back(kv.first);
}
map_.clear();
}
return E_OK;
}
void PreferencesImpl::Flush()
{
std::shared_ptr<PreferencesImpl::MemoryToDiskRequest> request = commitToMemory();
request->isSyncRequest_ = false;
taskPool_.Schedule(
std::string("PreferencesImpl"), std::bind(&PreferencesImpl::WriteToDiskFile, std::ref(*this), request));
notifyPreferencesObserver(*request);
}
int PreferencesImpl::FlushSync()
{
std::shared_ptr<PreferencesImpl::MemoryToDiskRequest> request = commitToMemory();
request->isSyncRequest_ = true;
taskPool_.Schedule(
std::string("PreferencesImpl"), std::bind(&PreferencesImpl::WriteToDiskFile, std::ref(*this), request));
std::unique_lock<std::mutex> lock(request->reqMutex_);
request->reqCond_.wait(lock, [request] { return request->handled_; });
if (request->wasWritten_) {
LOG_DEBUG("%{private}s:%{public}" PRId64 " written", filePath_.c_str(), request->memoryStateGeneration_);
}
notifyPreferencesObserver(*request);
return request->writeToDiskResult_;
}
std::shared_ptr<PreferencesImpl::MemoryToDiskRequest> PreferencesImpl::commitToMemory()
{
std::lock_guard<std::mutex> lock(mutex_);
int64_t memoryStateGeneration = -1;
std::list<std::string> keysModified;
std::vector<std::weak_ptr<PreferencesObserver>> preferencesObservers;
std::map<std::string, PreferencesValue> writeToDiskMap;
writeToDiskMap = map_;
if (!modifiedKeys_.empty()) {
currentMemoryStateGeneration_++;
keysModified = modifiedKeys_;
modifiedKeys_.clear();
}
memoryStateGeneration = currentMemoryStateGeneration_;
preferencesObservers = preferencesObservers_;
return std::make_shared<MemoryToDiskRequest>(
writeToDiskMap, keysModified, preferencesObservers, memoryStateGeneration);
}
void PreferencesImpl::notifyPreferencesObserver(const PreferencesImpl::MemoryToDiskRequest &request)
{
if ((request.preferencesObservers_.empty()) || (request.keysModified_.empty())) {
return;
}
for (auto key = request.keysModified_.begin(); key != request.keysModified_.end(); ++key) {
for (auto it = request.preferencesObservers_.begin(); it != request.preferencesObservers_.end(); ++it) {
std::weak_ptr<PreferencesObserver> weakPreferencesObserver = *it;
if (std::shared_ptr<PreferencesObserver> sharedPreferencesObserver = weakPreferencesObserver.lock()) {
sharedPreferencesObserver->OnChange(*this, *key);
}
}
}
}
PreferencesImpl::MemoryToDiskRequest::MemoryToDiskRequest(
const std::map<std::string, PreferencesValue> &writeToDiskMap, const std::list<std::string> &keysModified,
const std::vector<std::weak_ptr<PreferencesObserver>> preferencesObservers, int64_t memStataGeneration)
{
writeToDiskMap_ = writeToDiskMap;
keysModified_ = keysModified;
preferencesObservers_ = preferencesObservers;
memoryStateGeneration_ = memStataGeneration;
isSyncRequest_ = false;
handled_ = false;
wasWritten_ = false;
writeToDiskResult_ = E_ERROR;
}
void PreferencesImpl::MemoryToDiskRequest::SetDiskWriteResult(bool wasWritten, int result)
{
writeToDiskResult_ = result;
wasWritten_ = wasWritten;
handled_ = true;
reqCond_.notify_one();
}
} // End of namespace NativePreferences
} // End of namespace OHOS

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2021 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 "preferences_observer.h"
namespace OHOS {
namespace NativePreferences {
PreferencesObserver::~PreferencesObserver()
{
}
} // End of namespace NativePreferences
} // End of namespace OHOS

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2021 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 "preferences_value.h"
namespace OHOS {
namespace NativePreferences {
PreferencesValue::PreferencesValue(int value)
{
data_ = value;
}
PreferencesValue::PreferencesValue(int64_t value)
{
data_ = value;
}
PreferencesValue::PreferencesValue(float value)
{
data_ = value;
}
PreferencesValue::PreferencesValue(bool value)
{
data_ = value;
}
PreferencesValue::PreferencesValue(std::string value)
{
data_ = value;
}
bool PreferencesValue::IsInt() const
{
auto pVal = std::get_if<int>(&data_);
return (pVal != nullptr);
}
bool PreferencesValue::IsLong() const
{
auto pVal = std::get_if<int64_t>(&data_);
return (pVal != nullptr);
}
bool PreferencesValue::IsFloat() const
{
auto pVal = std::get_if<float>(&data_);
return (pVal != nullptr);
}
bool PreferencesValue::IsBool() const
{
auto pVal = std::get_if<bool>(&data_);
return (pVal != nullptr);
}
bool PreferencesValue::IsString() const
{
auto pVal = std::get_if<std::string>(&data_);
return (pVal != nullptr);
}
PreferencesValue::operator int()
{
return std::get<int>(data_);
}
PreferencesValue::operator int64_t()
{
return std::get<int64_t>(data_);
}
PreferencesValue::operator float()
{
return std::get<float>(data_);
}
PreferencesValue::operator bool()
{
return std::get<bool>(data_);
}
PreferencesValue::operator std::string()
{
return std::get<std::string>(data_);
}
bool PreferencesValue::operator==(const PreferencesValue &value)
{
return (this->data_ == value.data_);
}
} // End of namespace NativePreferences
} // End of namespace OHOS

View File

@ -0,0 +1,368 @@
/*
* Copyright (C) 2021 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 "preferences_xml_utils.h"
#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include "libxml/parser.h"
#include "logger.h"
namespace OHOS {
namespace NativePreferences {
static bool ParseNodeElement(const xmlNode *node, Element &element);
static bool ParsePrimitiveNodeElement(const xmlNode *node, Element &element);
static bool ParseStringNodeElement(const xmlNode *node, Element &element);
static bool ParseSetNodeElement(const xmlNode *node, Element &element);
static xmlNode *CreateElementNode(Element &element);
static xmlNode *CreatePrimitiveNode(Element &element);
static xmlNode *CreateStringNode(Element &element);
static xmlNode *CreateSetNode(Element &element);
/* static */
bool PreferencesXmlUtils::ReadSettingXml(const std::string &fileName, std::vector<Element> &settings)
{
LOG_DEBUG("Read setting xml %{private}s start.", fileName.c_str());
if (fileName.size() == 0) {
LOG_ERROR("The length of the file name is 0.");
return false;
}
char path[PATH_MAX + 1] = { 0x00 };
if (strlen(fileName.c_str()) > PATH_MAX || realpath(fileName.c_str(), path) == nullptr) {
LOG_ERROR("The file name is incorrect.");
return false;
}
const char *pathString = path;
xmlDoc *doc = xmlReadFile(pathString, "UTF-8", XML_PARSE_NOBLANKS);
if (doc == NULL) {
LOG_ERROR("The file name is incorrect.");
return false;
}
xmlNode *root = xmlDocGetRootElement(doc);
if (!root || xmlStrcmp(root->name, reinterpret_cast<const xmlChar *>("preferences"))) {
xmlFreeDoc(doc);
LOG_ERROR("Failed to obtain the XML root element.");
return false;
}
bool success = true;
const xmlNode *cur = NULL;
for (cur = root->children; cur != NULL; cur = cur->next) {
Element element;
if (ParseNodeElement(cur, element)) {
settings.push_back(element);
} else {
success = false;
LOG_ERROR("The error occurred during getting xml child elements.");
break;
}
}
/* free the document */
xmlFreeDoc(doc);
LOG_DEBUG("Read setting xml %{private}s end.", fileName.c_str());
return success;
}
/* static */
bool ParseNodeElement(const xmlNode *node, Element &element)
{
if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("int")) ||
!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("long")) ||
!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("bool")) ||
!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("float"))) {
return ParsePrimitiveNodeElement(node, element);
}
if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("string"))) {
return ParseStringNodeElement(node, element);
}
if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("set"))) {
return ParseSetNodeElement(node, element);
}
LOG_ERROR("An unsupported element type was encountered in parsing = %{public}s.", node->name);
return false;
}
/* static */
bool ParsePrimitiveNodeElement(const xmlNode *node, Element &element)
{
if (node == NULL) {
return false;
}
xmlChar *key = xmlGetProp(node, reinterpret_cast<const xmlChar *>("key"));
xmlChar *value = xmlGetProp(node, reinterpret_cast<const xmlChar *>("value"));
bool success = false;
if (key != NULL && value != NULL) {
element.tag_ = std::string(reinterpret_cast<const char *>(node->name));
element.key_ = std::string(reinterpret_cast<char *>(key));
element.value_ = std::string(reinterpret_cast<char *>(value));
success = true;
} else {
LOG_ERROR("Failed to obtain a valid key or value when parsing %{public}s.", node->name);
}
if (key != NULL) {
xmlFree(key);
}
if (value != NULL) {
xmlFree(value);
}
return success;
}
/* static */
bool ParseStringNodeElement(const xmlNode *node, Element &element)
{
if (node == NULL) {
return false;
}
xmlChar *key = xmlGetProp(node, (const xmlChar *)"key");
xmlChar *text = xmlNodeGetContent(node);
bool success = false;
if (text != NULL) {
element.tag_ = std::string(reinterpret_cast<const char *>(node->name));
if (key != NULL) {
element.key_ = std::string(reinterpret_cast<char *>(key));
}
element.value_ = std::string(reinterpret_cast<char *>(text));
success = true;
} else {
LOG_ERROR("Failed to obtain a valid key or value when parsing a String element.");
}
if (key != NULL) {
xmlFree(key);
}
if (text != NULL) {
xmlFree(text);
}
return success;
}
/* static */
bool ParseSetNodeElement(const xmlNode *node, Element &element)
{
if (node == NULL) {
return false;
}
xmlChar *key = xmlGetProp(node, (const xmlChar *)"key");
const xmlNode *children = node->children;
bool success = false;
if (key != NULL) {
element.tag_ = std::string(reinterpret_cast<const char *>(node->name));
element.key_ = std::string(reinterpret_cast<char *>(key));
const xmlNode *cur = NULL;
bool finishTravelChild = true;
for (cur = children; cur != NULL; cur = cur->next) {
Element child;
if (ParseNodeElement(cur, child)) {
element.children_.push_back(child);
} else {
finishTravelChild = false;
LOG_ERROR("Failed to parse the Set element and could not be completed successfully.");
break;
}
}
success = finishTravelChild;
} else {
LOG_ERROR("Failed to obtain a valid key or value when parsing a Set element.");
}
if (key != NULL) {
xmlFree(key);
}
return success;
}
/* static */
bool PreferencesXmlUtils::WriteSettingXml(const std::string &fileName, std::vector<Element> &settings)
{
LOG_DEBUG("Write setting xml %{private}s start.", fileName.c_str());
if (fileName.size() == 0) {
LOG_ERROR("The length of the file name is 0.");
return false;
}
// define doc and root Node
xmlDoc *doc = xmlNewDoc(BAD_CAST "1.0");
if (doc == NULL) {
LOG_ERROR("Failed to initialize the xmlDoc.");
return false;
}
xmlNode *root_node = xmlNewNode(NULL, BAD_CAST "preferences");
if (root_node == NULL) {
LOG_ERROR("The xmlDoc failed to initialize the root node.");
xmlFreeDoc(doc);
return false;
}
xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "1.0");
// set root node
xmlDocSetRootElement(doc, root_node);
// set children node
for (Element element : settings) {
xmlNode *node = CreateElementNode(element);
if (node == NULL) {
LOG_ERROR("The xmlDoc failed to initialize the element node.");
xmlFreeDoc(doc);
return false;
}
if (root_node == NULL || xmlAddChild(root_node, node) == NULL) {
/* free node in case of error */
LOG_ERROR("The xmlDoc failed to add the child node.");
xmlFreeNode(node);
xmlFreeDoc(doc);
return false;
}
}
/* 1: formatting spaces are added. */
int result = xmlSaveFormatFileEnc(fileName.c_str(), doc, "UTF-8", 1);
xmlFreeDoc(doc);
if (result > 0) {
LimitXmlPermission(fileName);
}
LOG_DEBUG("Write setting xml %{private}s end.", fileName.c_str());
return (result > 0) ? true : false;
}
/* static */
xmlNode *CreateElementNode(Element &element)
{
if ((element.tag_.compare("int") == 0) || (element.tag_.compare("long") == 0) ||
(element.tag_.compare("float") == 0) || (element.tag_.compare("bool") == 0)) {
return CreatePrimitiveNode(element);
}
if (element.tag_.compare("string") == 0) {
return CreateStringNode(element);
}
if (element.tag_.compare("set") == 0) {
return CreateSetNode(element);
}
LOG_ERROR("An unsupported element type was encountered in parsing = %{public}s.", element.tag_.c_str());
return nullptr;
}
/* static */
xmlNode *CreatePrimitiveNode(Element &element)
{
xmlNode *node = xmlNewNode(NULL, BAD_CAST element.tag_.c_str());
if (node == NULL) {
LOG_ERROR("The xmlDoc failed to initialize the primitive element node.");
return nullptr;
}
const char *key = element.key_.c_str();
xmlNewProp(node, BAD_CAST "key", BAD_CAST key);
const char *value = element.value_.c_str();
xmlNewProp(node, BAD_CAST "value", BAD_CAST value);
return node;
}
xmlNode *CreateStringNode(Element &element)
{
xmlNode *node = xmlNewNode(NULL, BAD_CAST element.tag_.c_str());
if (node == NULL) {
LOG_ERROR("The xmlDoc failed to initialize the string element node.");
return nullptr;
}
if (!element.key_.empty()) {
const char *key = element.key_.c_str();
xmlNewProp(node, BAD_CAST "key", BAD_CAST key);
}
const char *value = element.value_.c_str();
xmlNodePtr text = xmlNewText(BAD_CAST value);
if (xmlAddChild(node, text) == NULL) {
xmlFreeNode(text);
}
return node;
}
xmlNode *CreateSetNode(Element &element)
{
xmlNode *node = xmlNewNode(NULL, BAD_CAST element.tag_.c_str());
if (node == NULL) {
LOG_ERROR("The xmlDoc failed to initialize the set element node.");
return nullptr;
}
const char *key = element.key_.c_str();
xmlNewProp(node, BAD_CAST "key", BAD_CAST key);
for (Element child : element.children_) {
xmlNode *childNode = CreateElementNode(child);
if (childNode == NULL) {
continue;
}
if (xmlAddChild(node, childNode) == NULL) {
xmlFreeNode(childNode);
}
}
return node;
}
void PreferencesXmlUtils::LimitXmlPermission(const std::string &fileName)
{
/* clear execute permission of owner, clear execute permission of group, clear all permission of group. */
struct stat fileStat = { 0 };
if (stat(fileName.c_str(), &fileStat) != 0) {
LOG_ERROR("Failed to obtain stat of file, errno:%{public}d.", errno);
return;
}
if ((fileStat.st_mode & (S_IXUSR | S_IXGRP | S_IRWXO)) != 0) {
int result = chmod(fileName.c_str(), fileStat.st_mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
if (result != 0) {
LOG_ERROR("Failed to chmod file, errno:%{public}d.", errno);
}
}
}
void PreferencesXmlUtils::XmlInitParser()
{
xmlInitParser();
LOG_DEBUG("Xml parser get ready.");
}
void PreferencesXmlUtils::XmlCleanupParser()
{
xmlCleanupParser();
LOG_DEBUG("Xml parser clean up.");
}
} // End of namespace NativePreferences
} // End of namespace OHOS

View File

@ -0,0 +1,310 @@
/*
* Copyright (c) 2021 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 "task_pool.h"
#include "logger.h"
#include "preferences_errno.h"
namespace OHOS {
namespace NativePreferences {
constexpr int TaskPool::IDLE_WAIT_PERIOD;
TaskPool::TaskPool(int maxThreads, int minThreads)
: genericTasks_(false), genericTaskCount_(0), queuedTaskCount_(0), isStarted_(false), isStopping_(false),
isGenericThreadIdle_(false), maxThreads_(maxThreads), minThreads_(minThreads), curThreads_(0), idleThreads_(0)
{
}
TaskPool::~TaskPool()
{
}
int TaskPool::Start()
{
if (maxThreads_ < minThreads_) {
LOG_ERROR("Start task pool failed, maxThreads(%d) < minThreads(%d).", maxThreads_, minThreads_);
return -E_INVALID_ARGS;
}
if (maxThreads_ <= 0) {
LOG_ERROR("Start task pool failed, maxThreads(%d) <= 0.", maxThreads_);
return -E_INVALID_ARGS;
}
if (minThreads_ < 0) {
LOG_ERROR("Start task pool failed, minThreads(%d) < 0.", minThreads_);
return -E_INVALID_ARGS;
}
std::lock_guard<std::mutex> guard(tasksMutex_);
isStarted_ = true; // parameters checked ok.
isStopping_ = false;
int errCode = SpawnThreads(true);
if (errCode != E_OK) {
LOG_WARN("Spawn threads failed when starting the task pool.");
// ignore the error, we will try when schedule().
}
return E_OK;
}
void TaskPool::Stop()
{
std::unique_lock<std::mutex> lock(tasksMutex_);
if (!isStarted_) {
return;
}
isStopping_ = true;
hasTasks_.notify_all();
allThreadsExited_.wait(lock, [this]() { return this->curThreads_ <= 0; });
isStarted_ = false;
}
int TaskPool::Schedule(const Task &task)
{
if (!task) {
return -E_INVALID_ARGS;
}
std::lock_guard<std::mutex> guard(tasksMutex_);
if (!isStarted_) {
LOG_ERROR("Schedule failed, the task pool is not started.");
return -E_NOT_PERMIT;
}
if (isStopping_) {
LOG_ERROR("Schedule failed, the task pool is stopping.");
return -E_STALE;
}
if (genericTaskCount_ == INT_MAX) {
LOG_ERROR("Schedule failed, the task pool is full.");
return E_ERROR;
}
genericTasks_.PutTask(task);
++genericTaskCount_;
hasTasks_.notify_one();
TryToSpawnThreads();
return E_OK;
}
int TaskPool::Schedule(const std::string &queueTag, const Task &task)
{
if (!task) {
return -E_INVALID_ARGS;
}
std::lock_guard<std::mutex> guard(tasksMutex_);
if (!isStarted_) {
LOG_ERROR("Schedule failed, the task pool is not started.");
return -E_NOT_PERMIT;
}
if (isStopping_) {
LOG_ERROR("Schedule failed, the task pool is stopping.");
return -E_STALE;
}
if (queuedTaskCount_ == INT_MAX) {
LOG_ERROR("Schedule failed, the task pool is full.");
return E_ERROR;
}
queuedTasks_[queueTag].PutTask(task);
++queuedTaskCount_;
hasTasks_.notify_all();
TryToSpawnThreads();
return E_OK;
}
void TaskPool::ShrinkMemory(const std::string &tag)
{
std::lock_guard<std::mutex> guard(tasksMutex_);
auto iter = queuedTasks_.find(tag);
if (iter != queuedTasks_.end()) {
if (iter->second.IsEmptyAndUnlocked()) {
queuedTasks_.erase(iter);
}
}
}
void TaskPool::Report()
{
std::lock_guard<std::mutex> guard(tasksMutex_);
LOG_INFO("[Task pool report:1] maxThreads:%d, minThreads:%d, curThreads:%d, "
"idleThreads:%d, genericTaskCount:%d, queuedTaskCount:%d.",
maxThreads_, minThreads_, curThreads_, idleThreads_, genericTaskCount_, queuedTaskCount_);
LOG_INFO("[Task pool report:2] taskQueueCount:%zu.", queuedTasks_.size());
}
bool TaskPool::IdleExit(std::unique_lock<std::mutex> &lock)
{
if (isStopping_) {
return true;
}
++idleThreads_;
bool isGenericWorker = IsGenericWorker();
if (!isGenericWorker && (curThreads_ > minThreads_)) {
std::cv_status status = hasTasks_.wait_for(lock, std::chrono::seconds(IDLE_WAIT_PERIOD));
if (status == std::cv_status::timeout && genericTaskCount_ <= 0) {
--idleThreads_;
return true;
}
} else {
if (isGenericWorker) {
isGenericThreadIdle_ = true;
hasTasks_.notify_all();
}
hasTasks_.wait(lock);
if (isGenericWorker) {
isGenericThreadIdle_ = false;
}
}
--idleThreads_;
return false;
}
void TaskPool::SetThreadFree()
{
for (auto &pair : queuedTasks_) {
TaskQueue *tq = &pair.second;
tq->ReleaseLock();
}
}
Task TaskPool::ReapTask(TaskQueue *&queue)
{
Task task = genericTasks_.GetTaskAutoLock();
if (task != nullptr) {
queue = nullptr;
return task;
}
queue = nullptr;
if (IsGenericWorker() && (curThreads_ > 1)) { // 1 indicates self.
SetThreadFree();
return nullptr;
}
for (auto &pair : queuedTasks_) {
TaskQueue *tq = &pair.second;
task = tq->GetTaskAutoLock();
if (task != nullptr) {
queue = tq;
return task;
}
}
return nullptr;
}
int TaskPool::GetTask(Task &task, TaskQueue *&queue)
{
std::unique_lock<std::mutex> lock(tasksMutex_);
while (true) {
task = ReapTask(queue);
if (task != nullptr) {
return E_OK;
}
if (IdleExit(lock)) {
break;
}
}
return E_OK;
}
int TaskPool::SpawnThreads(bool isStart)
{
if (!isStarted_) {
LOG_ERROR("Spawn task pool threads failed, pool is not started.");
return -E_NOT_PERMIT;
}
if (curThreads_ >= maxThreads_) {
// the pool is full of threads.
return E_OK;
}
int limits = isStart ? minThreads_ : (curThreads_ + 1);
while (curThreads_ < limits) {
++curThreads_;
std::thread thread([this]() { TaskWorker(); });
LOG_INFO("Spawn task pool threads, min:%d cur:%d max:%d", minThreads_, curThreads_, maxThreads_);
thread.detach();
}
return E_OK;
}
bool TaskPool::IsGenericWorker() const
{
return genericThread_ == std::this_thread::get_id();
}
void TaskPool::BecomeGenericWorker()
{
std::lock_guard<std::mutex> guard(tasksMutex_);
if (genericThread_ == std::thread::id()) {
genericThread_ = std::this_thread::get_id();
}
}
void TaskPool::ExitGenericWorker()
{
std::lock_guard<std::mutex> guard(tasksMutex_);
if (IsGenericWorker()) {
genericThread_ = std::thread::id();
}
--curThreads_;
allThreadsExited_.notify_all();
LOG_INFO("Task pool thread exit, min:%d cur:%d max:%d, genericTaskCount:%d, queuedTaskCount:%d.", minThreads_,
curThreads_, maxThreads_, genericTaskCount_, queuedTaskCount_);
}
void TaskPool::TaskWorker()
{
BecomeGenericWorker();
while (true) {
TaskQueue *taskQueue = nullptr;
Task task = nullptr;
int errCode = GetTask(task, taskQueue);
if (errCode != E_OK) {
LOG_ERROR("Thread worker gets task failed, err:'%d'.", errCode);
break;
}
if (task == nullptr) {
// Idle thread exit.
break;
}
task();
FinishExecuteTask(taskQueue);
}
ExitGenericWorker();
}
void TaskPool::FinishExecuteTask(TaskQueue *taskQueue)
{
std::lock_guard<std::mutex> guard(tasksMutex_);
if (taskQueue != nullptr) {
taskQueue->ReleaseLock();
--queuedTaskCount_;
} else {
--genericTaskCount_;
}
}
void TaskPool::TryToSpawnThreads()
{
if ((curThreads_ >= maxThreads_) || (curThreads_ >= (queuedTaskCount_ + genericTaskCount_))) {
return;
}
SpawnThreads(false);
}
} // namespace NativePreferences
} // namespace OHOS

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2021 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 "task_queue.h"
namespace OHOS {
namespace NativePreferences {
TaskQueue::TaskQueue(bool lockable) : lockable_(lockable)
{
}
TaskQueue::~TaskQueue()
{
}
void TaskQueue::PutTask(const Task &task)
{
if (!task) {
return;
}
tasks_.push(task);
}
Task TaskQueue::GetTaskAutoLock()
{
if (lockable_) {
std::thread::id thisId = std::this_thread::get_id();
if (thisId != lockThread_) {
if (lockThread_ == std::thread::id()) {
lockThread_ = thisId;
} else {
return nullptr;
}
}
}
if (tasks_.empty()) {
ReleaseLock();
return nullptr;
}
// copy and return
Task task = tasks_.front();
tasks_.pop();
return task;
}
void TaskQueue::ReleaseLock()
{
if (!lockable_) {
return;
}
if (lockThread_ == std::this_thread::get_id()) {
lockThread_ = std::thread::id();
}
}
bool TaskQueue::IsEmptyAndUnlocked()
{
if (lockable_) {
if (lockThread_ != std::thread::id()) {
return false;
}
}
return tasks_.empty();
}
} // namespace NativePreferences
} // namespace OHOS

View File

@ -0,0 +1,52 @@
# Copyright (c) 2021 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("//build/test.gni")
module_output_path = "appdatamgr/native_preferences"
###############################################################################
config("module_private_config") {
visibility = [ ":*" ]
include_dirs = [
"../include/",
"//foundation/distributeddatamgr/appdatamgr/interfaces/innerkits/native_preferences/include",
]
}
ohos_unittest("NativePreferencesTest") {
module_out_path = module_output_path
sources = [
"unittest/preferences_file_test.cpp",
"unittest/preferences_helper_test.cpp",
"unittest/preferences_test.cpp",
]
configs = [ ":module_private_config" ]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
deps = [
"//foundation/distributeddatamgr/appdatamgr/interfaces/innerkits/native_preferences:native_preferences",
"//third_party/googletest:gtest_main",
]
}
###############################################################################
group("unittest") {
testonly = true
deps = [ ":NativePreferencesTest" ]
}
###############################################################################

View File

@ -0,0 +1,301 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include <thread>
#include "logger.h"
#include "preferences.h"
#include "preferences_errno.h"
#include "preferences_helper.h"
#include "preferences_xml_utils.h"
using namespace testing::ext;
using namespace OHOS::NativePreferences;
class PreferencesFileTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
};
void PreferencesFileTest::SetUpTestCase(void)
{
}
void PreferencesFileTest::TearDownTestCase(void)
{
}
void PreferencesFileTest::SetUp(void)
{
}
void PreferencesFileTest::TearDown(void)
{
}
/**
* @tc.name: NativePreferencesFileTest_001
* @tc.desc: normal testcase of backup file
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: liulinna
*/
HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_001, TestSize.Level1)
{
std::string file = "/data/test/test";
std::string backupFile = "/data/test/test.bak";
std::remove(file.c_str());
std::remove(backupFile.c_str());
std::vector<Element> settings;
Element elem;
elem.key_ = "intKey";
elem.tag_ = std::string("int");
elem.value_ = std::to_string(10);
settings.push_back(elem);
PreferencesXmlUtils::WriteSettingXml(backupFile, settings);
int errCode = E_OK;
std::shared_ptr<Preferences> pref = PreferencesHelper::GetPreferences(file, errCode);
EXPECT_EQ(errCode, E_OK);
int ret = pref->GetInt("intKey", 0);
EXPECT_EQ(ret, 10);
struct stat st = { 0 };
ret = stat(file.c_str(), &st);
EXPECT_EQ(ret, 0);
ret = (st.st_mode & (S_IXUSR | S_IXGRP | S_IRWXO));
EXPECT_EQ(ret, 0);
pref = nullptr;
ret = PreferencesHelper::DeletePreferences(file);
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: NativePreferencesFileTest_002
* @tc.desc: normal testcase of file permission
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: liulinna
*/
HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_002, TestSize.Level1)
{
std::string file = "/data/test/test";
std::remove(file.c_str());
int errCode = E_OK;
std::shared_ptr<Preferences> pref = PreferencesHelper::GetPreferences(file, errCode);
EXPECT_EQ(errCode, E_OK);
pref->PutInt("key1", 2);
pref->PutString("key2", "test");
int ret = pref->FlushSync();
EXPECT_EQ(ret, E_OK);
struct stat st = { 0 };
int result = stat(file.c_str(), &st);
EXPECT_EQ(result, 0);
result = st.st_mode & (S_IXUSR | S_IXGRP | S_IRWXO);
EXPECT_EQ(result, 0);
pref = nullptr;
result = PreferencesHelper::DeletePreferences(file);
EXPECT_EQ(result, E_OK);
}
/**
* @tc.name: NativePreferencesFileTest_003
* @tc.desc: test two same file path
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: liulinna
*/
HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_003, TestSize.Level1)
{
std::string absolutePath = "/data/test1";
std::string relativePath = "/data/test/../test1";
std::remove(absolutePath.c_str());
int errCode = E_OK;
std::shared_ptr<Preferences> pref1 = PreferencesHelper::GetPreferences(absolutePath, errCode);
EXPECT_EQ(errCode, E_OK);
errCode = E_OK;
std::shared_ptr<Preferences> pref2 = PreferencesHelper::GetPreferences(relativePath, errCode);
EXPECT_EQ(errCode, E_OK);
EXPECT_EQ(pref1, pref2);
pref1 = nullptr;
pref2 = nullptr;
int result = PreferencesHelper::DeletePreferences(absolutePath);
EXPECT_EQ(result, E_OK);
}
/**
* @tc.name: NativePreferencesFileTest_004
* @tc.desc: test FlushSync one times and five times
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: liulinna
*/
HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_004, TestSize.Level1)
{
std::string file = "/data/test/test";
int ret = PreferencesHelper::DeletePreferences(file);
EXPECT_EQ(ret, E_OK);
int errCode = E_OK;
std::shared_ptr<Preferences> pref = PreferencesHelper::GetPreferences(file, errCode);
EXPECT_EQ(errCode, E_OK);
pref->PutInt("intKey", 1);
pref->PutString("stringKey", "string1");
ret = pref->FlushSync();
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, pref->GetInt("intKey", 0));
EXPECT_EQ("string1", pref->GetString("stringKey", ""));
pref = nullptr;
ret = PreferencesHelper::RemovePreferencesFromCache("/data/test/test_helper");
EXPECT_EQ(ret, E_OK);
errCode = E_OK;
pref = PreferencesHelper::GetPreferences(file, errCode);
EXPECT_EQ(errCode, E_OK);
EXPECT_EQ(1, pref->GetInt("intKey", 0));
EXPECT_EQ("string1", pref->GetString("stringKey", ""));
pref->PutInt("intKey", 2);
pref->PutString("stringKey", "string2");
ret = pref->FlushSync();
EXPECT_EQ(ret, E_OK);
pref->PutInt("intKey", 3);
pref->PutString("stringKey", "string3");
ret = pref->FlushSync();
EXPECT_EQ(ret, E_OK);
pref->PutInt("intKey", 4);
pref->PutString("stringKey", "string4");
ret = pref->FlushSync();
EXPECT_EQ(ret, E_OK);
pref = PreferencesHelper::GetPreferences(file, errCode);
pref->PutInt("intKey", 5);
pref->PutString("stringKey", "string5");
ret = pref->FlushSync();
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(5, pref->GetInt("intKey", 0));
EXPECT_EQ("string5", pref->GetString("stringKey", ""));
pref = nullptr;
ret = PreferencesHelper::RemovePreferencesFromCache("/data/test/test_helper");
EXPECT_EQ(ret, E_OK);
errCode = E_OK;
pref = PreferencesHelper::GetPreferences(file, errCode);
EXPECT_EQ(errCode, E_OK);
EXPECT_EQ(5, pref->GetInt("intKey", 0));
EXPECT_EQ("string5", pref->GetString("stringKey", ""));
pref = nullptr;
ret = PreferencesHelper::DeletePreferences("/data/test/test_helper");
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: NativePreferencesFileTest_005
* @tc.desc: test Flush one times and five times
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: liulinna
*/
HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_005, TestSize.Level3)
{
std::string file = "/data/test/test";
int ret = PreferencesHelper::DeletePreferences(file);
EXPECT_EQ(ret, E_OK);
int errCode = E_OK;
std::shared_ptr<Preferences> pref = PreferencesHelper::GetPreferences(file, errCode);
EXPECT_EQ(errCode, E_OK);
pref->PutInt("intKey", 1);
pref->PutString("stringKey", "string1");
pref->Flush();
EXPECT_EQ(1, pref->GetInt("intKey", 0));
EXPECT_EQ("string1", pref->GetString("stringKey", ""));
std::this_thread::sleep_for(std::chrono::milliseconds(20));
pref = nullptr;
ret = PreferencesHelper::RemovePreferencesFromCache("/data/test/test_helper");
EXPECT_EQ(ret, E_OK);
errCode = E_OK;
pref = PreferencesHelper::GetPreferences(file, errCode);
EXPECT_EQ(errCode, E_OK);
EXPECT_EQ(1, pref->GetInt("intKey", 0));
EXPECT_EQ("string1", pref->GetString("stringKey", ""));
pref->PutInt("intKey", 2);
pref->PutString("stringKey", "string2");
pref->Flush();
pref->PutInt("intKey", 3);
pref->PutString("stringKey", "string3");
pref->Flush();
pref->PutInt("intKey", 4);
pref->PutString("stringKey", "string4");
pref->Flush();
pref->PutInt("intKey", 5);
pref->PutString("stringKey", "string5");
pref->Flush();
EXPECT_EQ(5, pref->GetInt("intKey", 0));
EXPECT_EQ("string5", pref->GetString("stringKey", ""));
std::this_thread::sleep_for(std::chrono::milliseconds(20));
pref = nullptr;
ret = PreferencesHelper::RemovePreferencesFromCache("/data/test/test_helper");
EXPECT_EQ(ret, E_OK);
errCode = E_OK;
pref = PreferencesHelper::GetPreferences(file, errCode);
EXPECT_EQ(errCode, E_OK);
EXPECT_EQ(5, pref->GetInt("intKey", 0));
EXPECT_EQ("string5", pref->GetString("stringKey", ""));
pref = nullptr;
ret = PreferencesHelper::DeletePreferences("/data/test/test_helper");
EXPECT_EQ(ret, E_OK);
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2021 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 "preferences_helper.h"
#include <gtest/gtest.h>
#include <cctype>
#include <iostream>
#include <string>
#include "logger.h"
#include "preferences.h"
#include "preferences_errno.h"
#include "preferences_observer.h"
using namespace testing::ext;
using namespace OHOS::NativePreferences;
class PreferencesHelperTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
};
void PreferencesHelperTest::SetUpTestCase(void)
{
}
void PreferencesHelperTest::TearDownTestCase(void)
{
}
void PreferencesHelperTest::SetUp(void)
{
}
void PreferencesHelperTest::TearDown(void)
{
}
/**
* @tc.name: NativePreferencesHelperTest_001
* @tc.desc: normal testcase of DeletePreferences
* @tc.type: FUNC
* @tc.require: SR000CU2BL
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesHelperTest, NativePreferencesHelperTest_001, TestSize.Level1)
{
int errCode = E_OK;
std::shared_ptr<Preferences> pref = PreferencesHelper::GetPreferences("/data/test/test_helper", errCode);
EXPECT_EQ(errCode, E_OK);
pref->PutInt("key1", 2);
pref->PutString("key2", "test");
int ret = pref->FlushSync();
EXPECT_EQ(ret, E_OK);
// ret = PreferencesHelper::RemovePreferencesFromCache("/data/test/test_helper");
// EXPECT_EQ(ret, E_PTR_EXIST_ANOTHER_HOLDER);
//
// ret = PreferencesHelper::DeletePreferences("/data/test/test_helper");
// EXPECT_EQ(ret, E_PTR_EXIST_ANOTHER_HOLDER);
pref = nullptr;
ret = PreferencesHelper::RemovePreferencesFromCache("/data/test/test_helper");
EXPECT_EQ(ret, E_OK);
ret = PreferencesHelper::DeletePreferences("/data/test/test_helper");
EXPECT_EQ(ret, E_OK);
}

View File

@ -0,0 +1,569 @@
/*
* Copyright (c) 2021 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 "preferences.h"
#include <gtest/gtest.h>
#include <cctype>
#include <iostream>
#include <string>
#include "logger.h"
#include "preferences_errno.h"
#include "preferences_helper.h"
#include "preferences_observer.h"
using namespace testing::ext;
using namespace OHOS::NativePreferences;
class PreferencesTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
static std::shared_ptr<Preferences> pref;
static const std::string LONG_KEY;
static const std::string KEY_TEST_INT_ELEMENT;
static const std::string KEY_TEST_LONG_ELEMENT;
static const std::string KEY_TEST_FLOAT_ELEMENT;
static const std::string KEY_TEST_BOOL_ELEMENT;
static const std::string KEY_TEST_STRING_ELEMENT;
};
std::shared_ptr<Preferences> PreferencesTest::pref = nullptr;
const std::string PreferencesTest::LONG_KEY = std::string(Preferences::MAX_KEY_LENGTH, std::toupper('a'));
;
const std::string PreferencesTest::KEY_TEST_INT_ELEMENT = "key_test_int";
const std::string PreferencesTest::KEY_TEST_LONG_ELEMENT = "key_test_long";
const std::string PreferencesTest::KEY_TEST_FLOAT_ELEMENT = "key_test_float";
const std::string PreferencesTest::KEY_TEST_BOOL_ELEMENT = "key_test_bool";
const std::string PreferencesTest::KEY_TEST_STRING_ELEMENT = "key_test_string";
void PreferencesTest::SetUpTestCase(void)
{
int errCode = E_OK;
pref = PreferencesHelper::GetPreferences("/data/test/test", errCode);
EXPECT_EQ(errCode, E_OK);
}
void PreferencesTest::TearDownTestCase(void)
{
pref = nullptr;
int ret = PreferencesHelper::DeletePreferences("/data/test/test");
EXPECT_EQ(ret, E_OK);
}
void PreferencesTest::SetUp(void)
{
}
void PreferencesTest::TearDown(void)
{
/* clear all data after every case */
if (pref) {
pref->Clear();
pref->Flush();
}
}
class PreferencesObserverCounter : public PreferencesObserver {
public:
virtual ~PreferencesObserverCounter();
void OnChange(Preferences &preferences, const std::string &key) override;
std::atomic_int notifyTimes;
static const std::vector<std::string> NOTIFY_KEYS_VECTOR;
};
PreferencesObserverCounter::~PreferencesObserverCounter()
{
}
void PreferencesObserverCounter::OnChange(Preferences &preferences, const std::string &key)
{
for (auto it = NOTIFY_KEYS_VECTOR.cbegin(); it != NOTIFY_KEYS_VECTOR.cend(); it++) {
if (key.compare(*it)) {
notifyTimes++;
break;
}
}
}
const std::vector<std::string> PreferencesObserverCounter::NOTIFY_KEYS_VECTOR = { PreferencesTest::KEY_TEST_INT_ELEMENT,
PreferencesTest::KEY_TEST_LONG_ELEMENT, PreferencesTest::KEY_TEST_FLOAT_ELEMENT,
PreferencesTest::KEY_TEST_BOOL_ELEMENT, PreferencesTest::KEY_TEST_STRING_ELEMENT };
/**
* @tc.name: NativePreferencesTest_001
* @tc.desc: normal testcase of FlushSync
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_001, TestSize.Level1)
{
pref->PutInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 2);
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test");
pref->FlushSync();
int ret1 = pref->GetInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 6);
EXPECT_EQ(ret1, 2);
std::string ret2 = pref->GetString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test1");
EXPECT_EQ(ret2, "test");
}
/**
* @tc.name: NativePreferencesTest_002
* @tc.desc: normal testcase of HasKey
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_002, TestSize.Level1)
{
bool ret = pref->HasKey(LONG_KEY + 'x');
EXPECT_EQ(ret, false);
ret = pref->HasKey(std::string());
EXPECT_EQ(ret, false);
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test");
ret = pref->HasKey(KEY_TEST_STRING_ELEMENT);
EXPECT_EQ(ret, true);
pref->Flush();
ret = pref->HasKey(KEY_TEST_STRING_ELEMENT);
EXPECT_EQ(ret, true);
}
/**
* @tc.name: NativePreferencesTest_003
* @tc.desc: normal testcase of pref
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_003, TestSize.Level1)
{
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test1");
std::string ret = pref->GetString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "defaultvalue");
EXPECT_EQ(ret, "test1");
pref->Flush();
ret = pref->GetString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "defaultvalue");
EXPECT_EQ(ret, "test1");
}
/**
* @tc.name: NativePreferencesTest_004
* @tc.desc: normal testcase of GetBool
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_004, TestSize.Level1)
{
bool ret = pref->GetBool(PreferencesTest::LONG_KEY + 'x', true);
EXPECT_EQ(ret, true);
ret = pref->GetBool("", true);
EXPECT_EQ(ret, true);
pref->PutBool(PreferencesTest::KEY_TEST_BOOL_ELEMENT, false);
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "false");
pref->Flush();
ret = pref->GetBool(PreferencesTest::KEY_TEST_BOOL_ELEMENT, true);
EXPECT_EQ(ret, false);
ret = pref->GetBool(PreferencesTest::KEY_TEST_STRING_ELEMENT, true);
EXPECT_EQ(ret, true);
}
/**
* @tc.name: NativePreferencesTest_005
* @tc.desc: normal testcase of GetFloat
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_005, TestSize.Level1)
{
float ret = pref->GetFloat(PreferencesTest::LONG_KEY + 'x', 3.0f);
EXPECT_EQ(ret, 3.0f);
ret = pref->GetFloat("", 3.0f);
EXPECT_EQ(ret, 3.0f);
pref->PutFloat(PreferencesTest::KEY_TEST_FLOAT_ELEMENT, 5.0f);
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "5.0");
pref->Flush();
ret = pref->GetFloat(PreferencesTest::KEY_TEST_FLOAT_ELEMENT, true);
EXPECT_EQ(ret, 5.0f);
ret = pref->GetFloat(PreferencesTest::KEY_TEST_STRING_ELEMENT, 3.0f);
EXPECT_EQ(ret, 3.0f);
}
/**
* @tc.name: NativePreferencesTest_006
* @tc.desc: normal testcase of GetInt
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_006, TestSize.Level1)
{
int ret = pref->GetInt(PreferencesTest::LONG_KEY + 'x', 35);
EXPECT_EQ(ret, 35);
ret = pref->GetInt("", 35);
EXPECT_EQ(ret, 35);
pref->PutInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 5);
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "5");
pref->Flush();
ret = pref->GetInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 3);
EXPECT_EQ(ret, 5);
ret = pref->GetInt(PreferencesTest::KEY_TEST_STRING_ELEMENT, 3);
EXPECT_EQ(ret, 3);
}
/**
* @tc.name: NativePreferencesTest_007
* @tc.desc: normal testcase of GetLong
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_007, TestSize.Level1)
{
int64_t ret = pref->GetLong(PreferencesTest::LONG_KEY + 'x', 35L);
EXPECT_EQ(ret, 35L);
ret = pref->GetLong("", 35L);
EXPECT_EQ(ret, 35L);
pref->PutInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 5);
pref->PutLong(PreferencesTest::KEY_TEST_LONG_ELEMENT, 5L);
pref->Flush();
ret = pref->GetLong(PreferencesTest::KEY_TEST_INT_ELEMENT, 3L);
EXPECT_EQ(ret, 3L);
ret = pref->GetLong(PreferencesTest::KEY_TEST_LONG_ELEMENT, 3L);
EXPECT_EQ(ret, 5L);
}
/**
* @tc.name: NativePreferencesTest_008
* @tc.desc: normal testcase of GetString
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_008, TestSize.Level1)
{
std::string ret = pref->GetString(PreferencesTest::LONG_KEY + 'x', "test");
EXPECT_EQ(ret, "test");
ret = pref->GetString("", "test");
EXPECT_EQ(ret, "test");
pref->PutInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 5);
pref->PutString(PreferencesTest::KEY_TEST_LONG_ELEMENT, "test");
pref->Flush();
ret = pref->GetString(PreferencesTest::KEY_TEST_INT_ELEMENT, "defaultvalue");
EXPECT_EQ(ret, "defaultvalue");
ret = pref->GetString(PreferencesTest::KEY_TEST_LONG_ELEMENT, "defaultvalue");
EXPECT_EQ(ret, "test");
}
/**
* @tc.name: NativePreferencesTest_009
* @tc.desc: normal testcase of GetDefValue
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_009, TestSize.Level1)
{
int ret0 = pref->GetInt(PreferencesTest::KEY_TEST_INT_ELEMENT, -1);
EXPECT_EQ(ret0, -1);
float ret1 = pref->GetFloat(PreferencesTest::KEY_TEST_FLOAT_ELEMENT, 1.0f);
EXPECT_EQ(ret1, 1.0f);
int64_t ret2 = pref->GetLong(PreferencesTest::KEY_TEST_LONG_ELEMENT, 10000L);
EXPECT_EQ(ret2, 10000L);
bool ret3 = pref->GetBool(PreferencesTest::KEY_TEST_BOOL_ELEMENT, true);
EXPECT_EQ(ret3, true);
std::string ret4 = pref->GetString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test");
EXPECT_EQ(ret4, "test");
}
/**
* @tc.name: NativePreferencesTest_010
* @tc.desc: normal testcase of PutBool
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_010, TestSize.Level1)
{
pref->PutBool(PreferencesTest::LONG_KEY + 'x', true);
pref->PutBool("", true);
pref->Flush();
bool ret = pref->GetBool(PreferencesTest::LONG_KEY + 'x', false);
EXPECT_EQ(ret, false);
ret = pref->GetBool("", false);
EXPECT_EQ(ret, false);
pref->PutBool(PreferencesTest::LONG_KEY, true);
pref->PutBool(PreferencesTest::KEY_TEST_BOOL_ELEMENT, true);
pref->Flush();
ret = pref->GetBool(PreferencesTest::LONG_KEY, false);
EXPECT_EQ(ret, true);
ret = pref->GetBool(PreferencesTest::KEY_TEST_BOOL_ELEMENT, false);
EXPECT_EQ(ret, true);
}
/**
* @tc.name: NativePreferencesTest_011
* @tc.desc: normal testcase of PutFloat
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_011, TestSize.Level1)
{
pref->PutFloat(PreferencesTest::LONG_KEY + 'x', 3.0f);
pref->PutFloat("", 3.0f);
pref->Flush();
float ret = pref->GetFloat(PreferencesTest::LONG_KEY + 'x', 1.0f);
EXPECT_EQ(ret, 1.0f);
ret = pref->GetFloat("", 1.0f);
EXPECT_EQ(ret, 1.0f);
pref->PutFloat(PreferencesTest::LONG_KEY, 3.0f);
pref->PutFloat(PreferencesTest::KEY_TEST_FLOAT_ELEMENT, 3.0f);
pref->Flush();
ret = pref->GetFloat(PreferencesTest::LONG_KEY, 1.0f);
EXPECT_EQ(ret, 3.0f);
ret = pref->GetFloat(PreferencesTest::KEY_TEST_FLOAT_ELEMENT, 1.0f);
EXPECT_EQ(ret, 3.0f);
}
/**
* @tc.name: NativePreferencesTest_012
* @tc.desc: normal testcase of PutInt
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_012, TestSize.Level1)
{
pref->PutInt(PreferencesTest::LONG_KEY + 'x', 3);
pref->PutInt("", 3);
pref->Flush();
int ret = pref->GetInt(PreferencesTest::LONG_KEY + 'x', 1);
EXPECT_EQ(ret, 1);
ret = pref->GetInt("", 1);
EXPECT_EQ(ret, 1);
pref->PutInt(PreferencesTest::LONG_KEY, 3);
pref->PutInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 3);
pref->Flush();
ret = pref->GetInt(PreferencesTest::LONG_KEY, 1);
EXPECT_EQ(ret, 3);
ret = pref->GetInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 1);
EXPECT_EQ(ret, 3);
}
/**
* @tc.name: NativePreferencesTest_013
* @tc.desc: normal testcase of PutLong
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_013, TestSize.Level1)
{
pref->PutLong(PreferencesTest::LONG_KEY + 'x', 3L);
pref->PutLong("", 3L);
pref->Flush();
int64_t ret = pref->GetLong(PreferencesTest::LONG_KEY + 'x', 1L);
EXPECT_EQ(ret, 1L);
ret = pref->GetLong("", 1L);
EXPECT_EQ(ret, 1L);
pref->PutLong(PreferencesTest::LONG_KEY, 3L);
pref->PutLong(PreferencesTest::KEY_TEST_LONG_ELEMENT, 3L);
pref->Flush();
ret = pref->GetLong(PreferencesTest::LONG_KEY, 1L);
EXPECT_EQ(ret, 3L);
ret = pref->GetLong(PreferencesTest::KEY_TEST_LONG_ELEMENT, 1L);
EXPECT_EQ(ret, 3L);
}
/**
* @tc.name: NativePreferencesTest_014
* @tc.desc: normal testcase of PutString
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_014, TestSize.Level1)
{
pref->PutString(PreferencesTest::LONG_KEY + 'x', "test");
pref->PutString("", "test");
pref->Flush();
std::string ret = pref->GetString(PreferencesTest::LONG_KEY + 'x', "defaultValue");
EXPECT_EQ(ret, "defaultValue");
ret = pref->GetString("", "defaultValue");
EXPECT_EQ(ret, "defaultValue");
pref->PutString(PreferencesTest::LONG_KEY, "test");
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test");
pref->Flush();
ret = pref->GetString(PreferencesTest::LONG_KEY, "defaultValue");
EXPECT_EQ(ret, "test");
ret = pref->GetString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "defaultValue");
EXPECT_EQ(ret, "test");
}
/**
* @tc.name: NativePreferencesTest_015
* @tc.desc: normal testcase of Delete
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_015, TestSize.Level1)
{
pref->PutString("test", "remove");
pref->Flush();
std::string ret = pref->GetString("test", "defaultValue");
EXPECT_EQ(ret, "remove");
pref->Delete("test");
pref->Flush();
ret = pref->GetString("test", "defaultValue");
EXPECT_EQ(ret, "defaultValue");
}
/**
* @tc.name: NativePreferencesTest_016
* @tc.desc: normal testcase of RegisterPreferencesObserver
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_016, TestSize.Level1)
{
std::shared_ptr<PreferencesObserver> counter =
std::shared_ptr<PreferencesObserver>(new PreferencesObserverCounter());
pref->RegisterObserver(counter);
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test");
pref->Flush();
EXPECT_EQ(static_cast<PreferencesObserverCounter *>(counter.get())->notifyTimes, 1);
/* same value */
pref->PutInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 2);
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test");
pref->Flush();
EXPECT_EQ(static_cast<PreferencesObserverCounter *>(counter.get())->notifyTimes, 2);
pref->UnRegisterObserver(counter);
}
/**
* @tc.name: NativePreferencesTest_017
* @tc.desc: normal testcase of UnRegisterPreferencesObserver
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_017, TestSize.Level1)
{
std::shared_ptr<PreferencesObserver> counter =
std::shared_ptr<PreferencesObserver>(new PreferencesObserverCounter());
pref->RegisterObserver(counter);
pref->PutInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 2);
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test");
pref->Flush();
EXPECT_EQ(static_cast<PreferencesObserverCounter *>(counter.get())->notifyTimes, 2);
pref->UnRegisterObserver(counter);
pref->PutInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 6);
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test1");
pref->Flush();
EXPECT_EQ(static_cast<PreferencesObserverCounter *>(counter.get())->notifyTimes, 2);
}
/**
* @tc.name: NativePreferencesTest_018
* @tc.desc: normal testcase of Clear
* @tc.type: FUNC
* @tc.require: AR000CU2BN
* @tc.author: xiuhongju
*/
HWTEST_F(PreferencesTest, NativePreferencesTest_018, TestSize.Level1)
{
pref->PutString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "test");
pref->PutInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 3);
pref->Flush();
pref->Clear();
std::string ret = pref->GetString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "defaultvalue");
EXPECT_EQ(ret, "defaultvalue");
int ret1 = pref->GetInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 0);
EXPECT_EQ(ret1, 0);
pref->Flush();
ret = pref->GetString(PreferencesTest::KEY_TEST_STRING_ELEMENT, "defaultvalue");
EXPECT_EQ(ret, "defaultvalue");
ret1 = pref->GetInt(PreferencesTest::KEY_TEST_INT_ELEMENT, 0);
EXPECT_EQ(ret1, 0);
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_LOG_PRINT_H
#define NATIVE_RDB_LOG_PRINT_H
#include "hilog/log.h"
namespace OHOS {
namespace NativeRdb {
static const OHOS::HiviewDFX::HiLogLabel RDB_LABEL = { LOG_CORE, 0xD001650, "NativeRDB" };
#define LOG_DEBUG(...) ((void)OHOS::HiviewDFX::HiLog::Debug(RDB_LABEL, __VA_ARGS__))
#define LOG_INFO(...) ((void)OHOS::HiviewDFX::HiLog::Info(RDB_LABEL, __VA_ARGS__))
#define LOG_WARN(...) ((void)OHOS::HiviewDFX::HiLog::Warn(RDB_LABEL, __VA_ARGS__))
#define LOG_ERROR(...) ((void)OHOS::HiviewDFX::HiLog::Error(RDB_LABEL, __VA_ARGS__))
#define LOG_FATAL(...) ((void)OHOS::HiviewDFX::HiLog::Fatal(RDB_LABEL, __VA_ARGS__))
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,144 @@
/*
* Copyright (c) 2021 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 "rdb_helper.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_store_impl.h"
#include "unistd.h"
namespace OHOS {
namespace NativeRdb {
std::shared_ptr<RdbStore> RdbHelper::GetRdbStore(
const RdbStoreConfig &config, int version, RdbOpenCallback &openCallback, int &errCode)
{
std::shared_ptr<RdbStore> rdbStore = RdbStoreImpl::Open(config, errCode);
if (rdbStore == nullptr) {
LOG_ERROR("RdbHelper GetRdbStore fail to open RdbStore");
return nullptr;
}
errCode = ProcessOpenCallback(*rdbStore, config, version, openCallback);
if (errCode != E_OK) {
LOG_ERROR("RdbHelper GetRdbStore ProcessOpenCallback fail");
return nullptr;
}
return rdbStore;
}
int RdbHelper::ProcessOpenCallback(
RdbStore &rdbStore, const RdbStoreConfig &config, int version, RdbOpenCallback &openCallback)
{
int currentVersion;
int errCode = rdbStore.GetVersion(currentVersion);
if (errCode != E_OK) {
return errCode;
}
if (version == currentVersion) {
return openCallback.OnOpen(rdbStore);
}
if (config.IsReadOnly()) {
LOG_ERROR("RdbHelper ProcessOpenCallback Can't upgrade read-only store");
return E_CANNT_UPDATE_READONLY;
}
errCode = rdbStore.BeginTransaction();
if (errCode != E_OK) {
return errCode;
}
if (currentVersion == 0) {
errCode = openCallback.OnCreate(rdbStore);
} else if (version > currentVersion) {
errCode = openCallback.OnUpgrade(rdbStore, currentVersion, version);
} else {
errCode = openCallback.OnDowngrade(rdbStore, currentVersion, version);
}
if (errCode == E_OK) {
errCode = rdbStore.SetVersion(version);
}
if (errCode != E_OK) {
rdbStore.MarkAsCommit();
rdbStore.EndTransaction();
return errCode;
}
errCode = rdbStore.MarkAsCommit();
if (errCode != E_OK) {
rdbStore.EndTransaction();
return errCode;
}
errCode = rdbStore.EndTransaction();
if (errCode != E_OK) {
return errCode;
}
return openCallback.OnOpen(rdbStore);
}
int RdbHelper::DeleteRdbStore(const std::string &dbFileName)
{
if (dbFileName.empty()) {
return E_EMPTY_FILE_NAME;
}
if (access(dbFileName.c_str(), F_OK) != 0) {
return E_OK; // not not exist
}
int result = remove(dbFileName.c_str());
if (result != 0) {
LOG_ERROR("RdbHelper DeleteRdbStore failed to delete the db file err = %{public}d", errno);
return E_REMOVE_FILE;
}
int errCode = E_OK;
std::string shmFileName = dbFileName + "-shm";
if (access(shmFileName.c_str(), F_OK) == 0) {
result = remove(shmFileName.c_str());
if (result < 0) {
LOG_ERROR("RdbHelper DeleteRdbStore failed to delete the shm file err = %{public}d", errno);
errCode = E_REMOVE_FILE;
}
}
std::string walFileName = dbFileName + "-wal";
if (access(walFileName.c_str(), F_OK) == 0) {
result = remove(walFileName.c_str());
if (result < 0) {
LOG_ERROR("RdbHelper DeleteRdbStore failed to delete the wal file err = %{public}d", errno);
errCode = E_REMOVE_FILE;
}
}
std::string journalFileName = dbFileName + "-journal";
if (access(journalFileName.c_str(), F_OK) == 0) {
result = remove(journalFileName.c_str());
if (result < 0) {
LOG_ERROR("RdbHelper DeleteRdbStore failed to delete the journal file err = %{public}d", errno);
errCode = E_REMOVE_FILE;
}
}
return errCode;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2021 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 "rdb_store_config.h"
namespace OHOS {
namespace NativeRdb {
RdbStoreConfig::RdbStoreConfig(
const std::string &path, StorageMode storageMode, bool isReadOnly, const std::vector<uint8_t> &encryptKey)
: path(path), storageMode(storageMode), readOnly(isReadOnly), encryptKey(encryptKey), journalMode("")
{
}
RdbStoreConfig::~RdbStoreConfig()
{
ClearEncryptKey();
}
void RdbStoreConfig::SetJournalMode(JournalMode journalMode)
{
switch (journalMode) {
case JournalMode::MODE_DELETE:
this->journalMode = "DELETE";
break;
case JournalMode::MODE_TRUNCATE:
this->journalMode = "TRUNCATE";
break;
case JournalMode::MODE_PERSIST:
this->journalMode = "PERSIST";
break;
case JournalMode::MODE_MEMORY:
this->journalMode = "MEMORY";
break;
case JournalMode::MODE_WAL:
this->journalMode = "WAL";
break;
case JournalMode::MODE_OFF:
this->journalMode = "OFF";
break;
default:
break;
}
}
std::string RdbStoreConfig::GetPath() const
{
return path;
}
StorageMode RdbStoreConfig::GetStorageMode() const
{
return storageMode;
}
std::string RdbStoreConfig::GetJournalMode() const
{
return journalMode;
}
bool RdbStoreConfig::IsReadOnly() const
{
return readOnly;
}
std::vector<uint8_t> RdbStoreConfig::GetEncryptKey() const
{
return encryptKey;
}
void RdbStoreConfig::ClearEncryptKey()
{
std::fill(encryptKey.begin(), encryptKey.end(), 0);
encryptKey.clear();
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,395 @@
/*
* Copyright (c) 2021 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 "rdb_store_impl.h"
#include <sstream>
#include "logger.h"
#include "rdb_errno.h"
#include "sqlite_sql_builder.h"
#include "sqlite_utils.h"
#include "step_result_set.h"
namespace OHOS {
namespace NativeRdb {
std::shared_ptr<RdbStore> RdbStoreImpl::Open(const RdbStoreConfig &config, int &errCode)
{
std::shared_ptr<RdbStoreImpl> rdbStore = std::make_shared<RdbStoreImpl>();
errCode = rdbStore->InnerOpen(config);
if (errCode != E_OK) {
return nullptr;
}
return rdbStore;
}
int RdbStoreImpl::InnerOpen(const RdbStoreConfig &config)
{
int errCode = E_OK;
connectionPool = SqliteConnectionPool::Create(config, errCode);
if (connectionPool == nullptr) {
return errCode;
}
return E_OK;
}
RdbStoreImpl::RdbStoreImpl() : connectionPool(nullptr)
{
}
RdbStoreImpl::~RdbStoreImpl()
{
if (connectionPool != nullptr) {
delete connectionPool;
}
threadMap.clear();
idleSessions.clear();
}
std::shared_ptr<StoreSession> RdbStoreImpl::GetThreadSession()
{
std::thread::id tid = std::this_thread::get_id();
std::lock_guard<std::mutex> lock(sessionMutex);
auto iter = threadMap.find(tid);
if (iter != threadMap.end()) {
iter->second.second++; // useCount++
return iter->second.first;
}
// get from idle stack
std::shared_ptr<StoreSession> session;
if (idleSessions.empty()) {
session = std::make_shared<StoreSession>(*connectionPool);
} else {
session = idleSessions.back();
idleSessions.pop_back();
}
threadMap.insert(std::make_pair(tid, std::make_pair(session, 1))); // useCount is 1
return session;
}
void RdbStoreImpl::ReleaseThreadSession()
{
std::thread::id tid = std::this_thread::get_id();
std::lock_guard<std::mutex> lock(sessionMutex);
auto iter = threadMap.find(tid);
if (iter == threadMap.end()) {
LOG_ERROR("RdbStoreImpl ReleaseThreadSession: no session found for the current thread");
return;
}
int &useCount = iter->second.second;
useCount--;
if (useCount > 0) {
return;
}
if (idleSessions.size() < MAX_IDLE_SESSION_SIZE) {
idleSessions.push_back(iter->second.first);
}
threadMap.erase(iter);
}
int RdbStoreImpl::Insert(int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues)
{
return InsertWithConflictResolution(outRowId, table, initialValues, ConflictResolution::ON_CONFLICT_NONE);
}
int RdbStoreImpl::Replace(int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues)
{
return InsertWithConflictResolution(outRowId, table, initialValues, ConflictResolution::ON_CONFLICT_REPLACE);
}
int RdbStoreImpl::InsertWithConflictResolution(int64_t &outRowId, const std::string &table,
const ValuesBucket &initialValues, ConflictResolution conflictResolution)
{
if (table.empty()) {
return E_EMPTY_TABLE_NAME;
}
if (initialValues.IsEmpty()) {
return E_EMPTY_VALUES_BUCKET;
}
std::string conflictClause;
int errCode = SqliteUtils::GetConflictClause(static_cast<int>(conflictResolution), conflictClause);
if (errCode != E_OK) {
return errCode;
}
std::stringstream sql;
sql << "INSERT" << conflictClause << " INTO " << table << '(';
std::map<std::string, ValueObject> valuesMap;
initialValues.GetAll(valuesMap);
std::vector<ValueObject> bindArgs;
for (auto iter = valuesMap.begin(); iter != valuesMap.end(); iter++) {
sql << ((iter == valuesMap.begin()) ? "" : ",");
sql << iter->first; // columnName
bindArgs.push_back(iter->second); // columnValue
}
sql << ") VALUES (";
for (size_t i = 0; i < valuesMap.size(); i++) {
sql << ((i == 0) ? "?" : ",?");
}
sql << ')';
std::shared_ptr<StoreSession> session = GetThreadSession();
errCode = session->ExecuteForLastInsertedRowId(outRowId, sql.str(), bindArgs);
ReleaseThreadSession();
return errCode;
}
int RdbStoreImpl::Update(int &changedRows, const std::string &table, const ValuesBucket &values,
const std::string &whereClause, const std::vector<std::string> &whereArgs)
{
return UpdateWithConflictResolution(
changedRows, table, values, whereClause, whereArgs, ConflictResolution::ON_CONFLICT_NONE);
}
int RdbStoreImpl::UpdateWithConflictResolution(int &changedRows, const std::string &table, const ValuesBucket &values,
const std::string &whereClause, const std::vector<std::string> &whereArgs, ConflictResolution conflictResolution)
{
if (table.empty()) {
return E_EMPTY_TABLE_NAME;
}
if (values.IsEmpty()) {
return E_EMPTY_VALUES_BUCKET;
}
std::string conflictClause;
int errCode = SqliteUtils::GetConflictClause(static_cast<int>(conflictResolution), conflictClause);
if (errCode != E_OK) {
return errCode;
}
std::stringstream sql;
sql << "UPDATE" << conflictClause << " " << table << " SET ";
std::map<std::string, ValueObject> valuesMap;
values.GetAll(valuesMap);
std::vector<ValueObject> bindArgs;
for (auto iter = valuesMap.begin(); iter != valuesMap.end(); iter++) {
sql << ((iter == valuesMap.begin()) ? "" : ",");
sql << iter->first << "=?"; // columnName
bindArgs.push_back(iter->second); // columnValue
}
if (whereClause.empty() == false) {
sql << " WHERE " << whereClause;
}
for (auto &iter : whereArgs) {
bindArgs.push_back(ValueObject(iter));
}
std::shared_ptr<StoreSession> session = GetThreadSession();
errCode = session->ExecuteForChangedRowCount(changedRows, sql.str(), bindArgs);
ReleaseThreadSession();
return errCode;
}
int RdbStoreImpl::Delete(int &deletedRows, const std::string &table, const std::string &whereClause,
const std::vector<std::string> &whereArgs)
{
if (table.empty()) {
return E_EMPTY_TABLE_NAME;
}
std::stringstream sql;
sql << "DELETE FROM " << table;
if (whereClause.empty() == false) {
sql << " WHERE " << whereClause;
}
std::vector<ValueObject> bindArgs;
for (auto &iter : whereArgs) {
bindArgs.push_back(ValueObject(iter));
}
std::shared_ptr<StoreSession> session = GetThreadSession();
int errCode = session->ExecuteForChangedRowCount(deletedRows, sql.str(), bindArgs);
ReleaseThreadSession();
return errCode;
}
std::unique_ptr<ResultSet> RdbStoreImpl::Query(int &errCode, bool distinct, const std::string &table,
const std::vector<std::string> &columns, const std::string &selection,
const std::vector<std::string> &selectionArgs, const std::string &groupBy, const std::string &having,
const std::string &orderBy, const std::string &limit)
{
std::string sql;
errCode =
SqliteSqlBuilder::BuildQueryString(distinct, table, columns, selection, groupBy, having, orderBy, limit, sql);
if (errCode != E_OK) {
return nullptr;
}
return QuerySql(sql, selectionArgs);
}
std::unique_ptr<ResultSet> RdbStoreImpl::QuerySql(const std::string &sql, const std::vector<std::string> &selectionArgs)
{
std::unique_ptr<ResultSet> resultSet = std::make_unique<StepResultSet>(shared_from_this(), sql, selectionArgs);
return resultSet;
}
int RdbStoreImpl::ExecuteSql(const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = CheckAttach(sql);
if (errCode != E_OK) {
return errCode;
}
std::shared_ptr<StoreSession> session = GetThreadSession();
errCode = session->ExecuteSql(sql, bindArgs);
if (errCode != E_OK) {
ReleaseThreadSession();
return errCode;
}
int sqlType = SqliteUtils::GetSqlStatementType(sql);
if (sqlType == SqliteUtils::STATEMENT_DDL) {
errCode = connectionPool->ReOpenAvailableReadConnections();
}
ReleaseThreadSession();
return errCode;
}
int RdbStoreImpl::ExecuteAndGetLong(int64_t &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
std::shared_ptr<StoreSession> session = GetThreadSession();
int errCode = session->ExecuteGetLong(outValue, sql, bindArgs);
ReleaseThreadSession();
return errCode;
}
int RdbStoreImpl::ExecuteAndGetString(
std::string &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
std::shared_ptr<StoreSession> session = GetThreadSession();
int errCode = session->ExecuteGetString(outValue, sql, bindArgs);
ReleaseThreadSession();
return errCode;
}
int RdbStoreImpl::GetVersion(int &version)
{
int64_t value;
int errCode = ExecuteAndGetLong(value, "PRAGMA user_version;", std::vector<ValueObject>());
version = static_cast<int>(value);
return errCode;
}
int RdbStoreImpl::SetVersion(int version)
{
std::string sql = "PRAGMA user_version = " + std::to_string(version);
return ExecuteSql(sql, std::vector<ValueObject>());
}
int RdbStoreImpl::BeginTransaction()
{
std::shared_ptr<StoreSession> session = GetThreadSession();
int errCode = session->BeginTransaction();
if (errCode != E_OK) {
ReleaseThreadSession();
return errCode;
}
return E_OK;
}
int RdbStoreImpl::MarkAsCommit()
{
std::shared_ptr<StoreSession> session = GetThreadSession();
int errCode = session->MarkAsCommit();
ReleaseThreadSession();
return errCode;
}
int RdbStoreImpl::EndTransaction()
{
std::shared_ptr<StoreSession> session = GetThreadSession();
int errCode = session->EndTransaction();
// release the session got in EndTransaction()
ReleaseThreadSession();
// release the session got in BeginTransaction()
ReleaseThreadSession();
return errCode;
}
bool RdbStoreImpl::IsInTransaction()
{
std::shared_ptr<StoreSession> session = GetThreadSession();
bool inTransaction = session->IsInTransaction();
ReleaseThreadSession();
return inTransaction;
}
int RdbStoreImpl::ChangeEncryptKey(const std::vector<uint8_t> &newKey)
{
return connectionPool->ChangeEncryptKey(newKey);
}
std::shared_ptr<SqliteStatement> RdbStoreImpl::BeginStepQuery(
int &errCode, const std::string sql, const std::vector<std::string> &bindArgs)
{
std::shared_ptr<StoreSession> session = GetThreadSession();
return session->BeginStepQuery(errCode, sql, bindArgs);
}
int RdbStoreImpl::EndStepQuery()
{
std::shared_ptr<StoreSession> session = GetThreadSession();
int err = session->EndStepQuery();
ReleaseThreadSession(); // release session got by EndStepQuery
ReleaseThreadSession(); // release session got by BeginStepQuery
return err;
}
int RdbStoreImpl::CheckAttach(const std::string &sql)
{
size_t index = sql.find_first_not_of(' ');
if (index == std::string::npos) {
return E_OK;
}
/* The first 3 characters can determine the type */
std::string sqlType = sql.substr(index, 3);
sqlType = SqliteUtils::StrToUpper(sqlType);
if (sqlType != "ATT") {
return E_OK;
}
std::string journalMode;
int errCode = ExecuteAndGetString(journalMode, "PRAGMA journal_mode", std::vector<ValueObject>());
if (errCode != E_OK) {
LOG_ERROR("RdbStoreImpl CheckAttach fail to get journal mode : %{public}d", errCode);
return errCode;
}
journalMode = SqliteUtils::StrToUpper(journalMode);
if (journalMode == "WAL") {
LOG_ERROR("RdbStoreImpl attach is not supported in WAL mode");
return E_NOT_SUPPROTED_ATTACH_IN_WAL_MODE;
}
return E_OK;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_RDB_STORE_IMPL_H
#define NATIVE_RDB_RDB_STORE_IMPL_H
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <thread>
#include "rdb_store.h"
#include "rdb_store_config.h"
#include "sqlite_connection_pool.h"
#include "sqlite_statement.h"
#include "store_session.h"
namespace OHOS {
namespace NativeRdb {
class RdbStoreImpl : public RdbStore, public std::enable_shared_from_this<RdbStoreImpl> {
public:
static std::shared_ptr<RdbStore> Open(const RdbStoreConfig &config, int &errCode);
RdbStoreImpl();
~RdbStoreImpl() override;
int Insert(int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues) override;
int Replace(int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues) override;
int InsertWithConflictResolution(int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues,
ConflictResolution conflictResolution) override;
int Update(int &changedRows, const std::string &table, const ValuesBucket &values, const std::string &whereClause,
const std::vector<std::string> &whereArgs) override;
int UpdateWithConflictResolution(int &changedRows, const std::string &table, const ValuesBucket &values,
const std::string &whereClause, const std::vector<std::string> &whereArgs,
ConflictResolution conflictResolution) override;
int Delete(int &deletedRows, const std::string &table, const std::string &whereClause,
const std::vector<std::string> &whereArgs) override;
std::unique_ptr<ResultSet> Query(int &errCode, bool distinct, const std::string &table,
const std::vector<std::string> &columns, const std::string &selection,
const std::vector<std::string> &selectionArgs, const std::string &groupBy, const std::string &having,
const std::string &orderBy, const std::string &limit) override;
std::unique_ptr<ResultSet> QuerySql(const std::string &sql, const std::vector<std::string> &selectionArgs) override;
int ExecuteSql(const std::string &sql, const std::vector<ValueObject> &bindArgs) override;
int ExecuteAndGetLong(int64_t &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs) override;
int ExecuteAndGetString(
std::string &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs) override;
int GetVersion(int &version) override;
int SetVersion(int version) override;
int BeginTransaction() override;
int MarkAsCommit() override;
int EndTransaction() override;
bool IsInTransaction() override;
int ChangeEncryptKey(const std::vector<uint8_t> &newKey) override;
std::shared_ptr<SqliteStatement> BeginStepQuery(
int &errCode, const std::string sql, const std::vector<std::string> &bindArgs);
int EndStepQuery();
private:
int InnerOpen(const RdbStoreConfig &config);
std::shared_ptr<StoreSession> GetThreadSession();
void ReleaseThreadSession();
int CheckAttach(const std::string &sql);
SqliteConnectionPool *connectionPool;
static const int MAX_IDLE_SESSION_SIZE = 5;
std::mutex sessionMutex;
std::map<std::thread::id, std::pair<std::shared_ptr<StoreSession>, int>> threadMap;
std::list<std::shared_ptr<StoreSession>> idleSessions;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2021 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 "sqlite_config.h"
#include "sqlite_global_config.h"
namespace OHOS {
namespace NativeRdb {
SqliteConfig::SqliteConfig(const RdbStoreConfig &config)
{
path = config.GetPath();
storageMode = config.GetStorageMode();
readOnly = config.IsReadOnly();
encryptKey = config.GetEncryptKey();
encrypted = !encryptKey.empty();
journalMode = config.GetJournalMode();
if (journalMode.empty()) {
journalMode = SqliteGlobalConfig::GetDefaultJournalMode();
}
}
SqliteConfig::~SqliteConfig()
{
ClearEncryptKey();
}
std::string SqliteConfig::GetPath() const
{
return path;
}
StorageMode SqliteConfig::GetStorageMode() const
{
return storageMode;
}
std::string SqliteConfig::GetJournalMode() const
{
return journalMode;
}
bool SqliteConfig::IsReadOnly() const
{
return readOnly;
}
bool SqliteConfig::IsEncrypted() const
{
return encrypted;
}
std::vector<uint8_t> SqliteConfig::GetEncryptKey() const
{
return encryptKey;
}
void SqliteConfig::UpdateEncryptKey(const std::vector<uint8_t> &newKey)
{
std::fill(encryptKey.begin(), encryptKey.end(), 0);
encryptKey = newKey;
}
void SqliteConfig::ClearEncryptKey()
{
std::fill(encryptKey.begin(), encryptKey.end(), 0);
encryptKey.clear();
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_SQLITE_CONFIG_H
#define NATIVE_RDB_SQLITE_CONFIG_H
#include <string>
#include <vector>
#include "rdb_store_config.h"
namespace OHOS {
namespace NativeRdb {
class SqliteConfig {
public:
explicit SqliteConfig(const RdbStoreConfig &config);
~SqliteConfig();
std::string GetPath() const;
StorageMode GetStorageMode() const;
std::string GetJournalMode() const;
bool IsReadOnly() const;
bool IsEncrypted() const;
std::vector<uint8_t> GetEncryptKey() const;
void UpdateEncryptKey(const std::vector<uint8_t> &newKey);
void ClearEncryptKey();
private:
std::string path;
StorageMode storageMode;
std::string journalMode;
bool readOnly;
bool encrypted;
std::vector<uint8_t> encryptKey;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,495 @@
/*
* Copyright (c) 2021 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 "sqlite_connection.h"
#include <sys/stat.h>
#include <cerrno>
#include "logger.h"
#include "rdb_errno.h"
#include "sqlite_errno.h"
#include "sqlite_global_config.h"
#include "sqlite_utils.h"
namespace OHOS {
namespace NativeRdb {
SqliteConnection *SqliteConnection::Open(const SqliteConfig &config, bool isWriteConnection, int &errCode)
{
auto connection = new SqliteConnection(isWriteConnection);
errCode = connection->InnerOpen(config);
if (errCode != E_OK) {
delete connection;
return nullptr;
}
return connection;
}
SqliteConnection::SqliteConnection(bool isWriteConnection)
: dbHandle(nullptr), isWriteConnection(isWriteConnection), isReadOnly(false), statement(), stepStatement(nullptr)
{
}
int SqliteConnection::InnerOpen(const SqliteConfig &config)
{
std::string dbPath;
if (config.GetStorageMode() == StorageMode::MODE_MEMORY) {
dbPath = SqliteGlobalConfig::GetMemoryDbPath();
} else if (config.GetPath().empty()) {
LOG_ERROR("SqliteConnection InnerOpen input empty database path");
return E_EMPTY_FILE_NAME;
} else if (config.GetPath().front() != '/') { // change this to starts_with() after c++20
LOG_ERROR("SqliteConnection InnerOpen input relative path");
return E_RELATIVE_PATH;
} else {
dbPath = config.GetPath();
}
stepStatement = std::make_shared<SqliteStatement>();
if (stepStatement == nullptr) {
return E_STEP_STATEMENT_NOT_INIT;
}
isReadOnly = !isWriteConnection || config.IsReadOnly();
int openFlags = config.IsReadOnly() ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
int errCode = sqlite3_open_v2(dbPath.c_str(), &dbHandle, openFlags, nullptr);
if (errCode != SQLITE_OK) {
LOG_ERROR("SqliteConnection InnerOpen fail to open database err = %{public}d", errCode);
return SQLiteError::ErrNo(errCode);
}
LimitPermission(dbPath);
errCode = Config(config);
if (errCode != E_OK) {
return errCode;
}
return E_OK;
}
int SqliteConnection::Config(const SqliteConfig &config)
{
if (config.GetStorageMode() == StorageMode::MODE_MEMORY) {
return E_OK;
}
int errCode = SetPageSize();
if (errCode != E_OK) {
return errCode;
}
std::vector<uint8_t> encryptKey = config.GetEncryptKey();
errCode = SetEncryptKey(encryptKey);
std::fill(encryptKey.begin(), encryptKey.end(), 0);
if (errCode != E_OK) {
return errCode;
}
errCode = SetJournalMode(config.GetJournalMode());
if (errCode != E_OK) {
return errCode;
}
errCode = SetJournalSizeLimit();
if (errCode != E_OK) {
return errCode;
}
errCode = SetAutoCheckpoint();
if (errCode != E_OK) {
return errCode;
}
return E_OK;
}
SqliteConnection::~SqliteConnection()
{
if (dbHandle != nullptr) {
statement.Finalize();
if (stepStatement != nullptr) {
stepStatement->Finalize();
}
int errCode = sqlite3_close(dbHandle);
if (errCode != SQLITE_OK) {
LOG_ERROR("SqliteConnection ~SqliteConnection: could not close database err = %{public}d", errCode);
}
}
}
int SqliteConnection::SetPageSize()
{
if (isReadOnly) {
return E_OK;
}
int targetValue = SqliteGlobalConfig::GetPageSize();
int64_t value;
int errCode = ExecuteGetLong(value, "PRAGMA page_size");
if (errCode != E_OK) {
LOG_ERROR("SqliteConnection SetPageSize fail to get page size : %{public}d", errCode);
return errCode;
}
if (value == targetValue) {
return E_OK;
}
errCode = ExecuteSql("PRAGMA page_size=" + std::to_string(targetValue));
if (errCode != E_OK) {
LOG_ERROR("SqliteConnection SetPageSize fail to set page size : %{public}d", errCode);
}
return errCode;
}
int SqliteConnection::SetEncryptKey(const std::vector<uint8_t> &encryptKey)
{
if (encryptKey.empty()) {
return E_OK;
}
int errCode = sqlite3_key(dbHandle, static_cast<const void *>(encryptKey.data()), encryptKey.size());
if (errCode != SQLITE_OK) {
LOG_ERROR("SqliteConnection SetEncryptKey fail, err = %{public}d", errCode);
return SQLiteError::ErrNo(errCode);
}
return E_OK;
}
int SqliteConnection::SetJournalMode(const std::string &journalMode)
{
if (isReadOnly) {
return E_OK;
}
std::string currentMode;
int errCode = ExecuteGetString(currentMode, "PRAGMA journal_mode");
if (errCode != E_OK) {
LOG_ERROR("SqliteConnection SetJournalMode fail to get journal mode : %{public}d", errCode);
return errCode;
}
currentMode = SqliteUtils::StrToUpper(currentMode);
if (currentMode != journalMode) {
std::string result;
int errorCode = ExecuteGetString(result, "PRAGMA journal_mode=" + journalMode);
if (errorCode != E_OK) {
LOG_ERROR("SqliteConnection SetJournalMode: fail to set journal mode err=%{public}d", errorCode);
return errorCode;
}
if (SqliteUtils::StrToUpper(result) != journalMode) {
LOG_ERROR("SqliteConnection SetJournalMode: result incorrect");
return E_EXECUTE_RESULT_INCORRECT;
}
}
if (journalMode == "WAL") {
errCode = SetWalSyncMode();
}
return errCode;
}
int SqliteConnection::SetJournalSizeLimit()
{
if (isReadOnly) {
return E_OK;
}
int targetValue = SqliteGlobalConfig::GetJournalFileSize();
int64_t currentValue;
int errCode = ExecuteGetLong(currentValue, "PRAGMA journal_size_limit");
if (errCode != E_OK) {
LOG_ERROR("SqliteConnection SetJournalSizeLimit fail to get journal_size_limit : %{public}d", errCode);
return errCode;
}
if (currentValue == targetValue) {
return E_OK;
}
int64_t result;
errCode = ExecuteGetLong(result, "PRAGMA journal_size_limit=" + std::to_string(targetValue));
if (errCode != E_OK) {
LOG_ERROR("SqliteConnection SetJournalSizeLimit fail to set journal_size_limit : %{public}d", errCode);
}
return errCode;
}
int SqliteConnection::SetAutoCheckpoint()
{
if (isReadOnly) {
return E_OK;
}
int targetValue = SqliteGlobalConfig::GetWalAutoCheckpoint();
int64_t value;
int errCode = ExecuteGetLong(value, "PRAGMA wal_autocheckpoint");
if (errCode != E_OK) {
LOG_ERROR("SqliteConnection SetAutoCheckpoint fail to get wal_autocheckpoint : %{public}d", errCode);
return errCode;
}
if (value == targetValue) {
return E_OK;
}
int64_t result;
errCode = ExecuteGetLong(result, "PRAGMA wal_autocheckpoint=" + std::to_string(targetValue));
if (errCode != E_OK) {
LOG_ERROR("SqliteConnection SetAutoCheckpoint fail to set wal_autocheckpoint : %{public}d", errCode);
}
return errCode;
}
int SqliteConnection::SetWalSyncMode()
{
std::string targetValue = SqliteGlobalConfig::GetWalSyncMode();
std::string value;
int errCode = ExecuteGetString(value, "PRAGMA synchronous");
if (errCode != E_OK) {
LOG_ERROR("SqliteConnection setWalSyncMode fail to get synchronous mode : %{public}d", errCode);
return errCode;
}
value = SqliteUtils::StrToUpper(value);
if (value == targetValue) {
return E_OK;
}
errCode = ExecuteSql("PRAGMA synchronous=" + targetValue);
if (errCode != E_OK) {
LOG_ERROR("SqliteConnection setWalSyncMode fail to set synchronous mode : %{public}d", errCode);
}
return errCode;
}
bool SqliteConnection::IsWriteConnection() const
{
return isWriteConnection;
}
int SqliteConnection::Prepare(const std::string &sql, bool &outIsReadOnly)
{
int errCode = statement.Prepare(dbHandle, sql);
if (errCode != E_OK) {
return errCode;
}
outIsReadOnly = statement.IsReadOnly();
return E_OK;
}
int SqliteConnection::PrepareAndBind(const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = statement.Prepare(dbHandle, sql);
if (errCode != E_OK) {
return errCode;
}
if (!isWriteConnection && !statement.IsReadOnly()) {
return E_EXECUTE_WRITE_IN_READ_CONNECTION;
}
errCode = statement.BindArguments(bindArgs);
return errCode;
}
int SqliteConnection::ExecuteSql(const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = PrepareAndBind(sql, bindArgs);
if (errCode != E_OK) {
return errCode;
}
errCode = statement.Step();
if (errCode == SQLITE_ROW) {
LOG_ERROR("SqliteConnection Execute : Queries can be performed using query or QuerySql methods only");
statement.ResetStatementAndClearBindings();
return E_QUERY_IN_EXECUTE;
} else if (errCode != SQLITE_DONE) {
LOG_ERROR("SqliteConnection Execute : err %{public}d", errCode);
statement.ResetStatementAndClearBindings();
return SQLiteError::ErrNo(errCode);
}
errCode = statement.ResetStatementAndClearBindings();
return errCode;
}
int SqliteConnection::ExecuteForChangedRowCount(
int &changedRows, const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = PrepareAndBind(sql, bindArgs);
if (errCode != E_OK) {
return errCode;
}
errCode = statement.Step();
if (errCode == SQLITE_ROW) {
LOG_ERROR("SqliteConnection ExecuteForChangedRowCount : Queries can be performed using query or QuerySql "
"methods only");
statement.ResetStatementAndClearBindings();
return E_QUERY_IN_EXECUTE;
} else if (errCode != SQLITE_DONE) {
LOG_ERROR("SqliteConnection ExecuteForChangedRowCount : failed %{public}d", errCode);
statement.ResetStatementAndClearBindings();
return SQLiteError::ErrNo(errCode);
}
changedRows = sqlite3_changes(dbHandle);
errCode = statement.ResetStatementAndClearBindings();
return errCode;
}
int SqliteConnection::ExecuteForLastInsertedRowId(
int64_t &outRowId, const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = PrepareAndBind(sql, bindArgs);
if (errCode != E_OK) {
return errCode;
}
errCode = statement.Step();
if (errCode == SQLITE_ROW) {
LOG_ERROR("SqliteConnection ExecuteForLastInsertedRowId : Queries can be performed using query or QuerySql "
"methods only");
statement.ResetStatementAndClearBindings();
return E_QUERY_IN_EXECUTE;
} else if (errCode != SQLITE_DONE) {
LOG_ERROR("SqliteConnection ExecuteForLastInsertedRowId : failed %{public}d", errCode);
statement.ResetStatementAndClearBindings();
return SQLiteError::ErrNo(errCode);
}
outRowId = (sqlite3_changes(dbHandle) > 0) ? sqlite3_last_insert_rowid(dbHandle) : -1;
errCode = statement.ResetStatementAndClearBindings();
return errCode;
}
int SqliteConnection::ExecuteGetLong(
int64_t &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = PrepareAndBind(sql, bindArgs);
if (errCode != E_OK) {
return errCode;
}
errCode = statement.Step();
if (errCode != SQLITE_ROW) {
statement.ResetStatementAndClearBindings();
return E_NO_ROW_IN_QUERY;
}
errCode = statement.GetColumnLong(0, outValue);
if (errCode != E_OK) {
statement.ResetStatementAndClearBindings();
return errCode;
}
errCode = statement.ResetStatementAndClearBindings();
return errCode;
}
int SqliteConnection::ExecuteGetString(
std::string &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = PrepareAndBind(sql, bindArgs);
if (errCode != E_OK) {
return errCode;
}
errCode = statement.Step();
if (errCode != SQLITE_ROW) {
statement.ResetStatementAndClearBindings();
return E_NO_ROW_IN_QUERY;
}
errCode = statement.GetColumnString(0, outValue);
if (errCode != E_OK) {
statement.ResetStatementAndClearBindings();
return errCode;
}
errCode = statement.ResetStatementAndClearBindings();
return errCode;
}
std::shared_ptr<SqliteStatement> SqliteConnection::BeginStepQuery(
int &errCode, const std::string &sql, const std::vector<std::string> &selectionArgs)
{
errCode = stepStatement->Prepare(dbHandle, sql);
if (errCode != E_OK) {
return nullptr;
}
std::vector<ValueObject> bindArgs;
for (auto item : selectionArgs) {
bindArgs.push_back(ValueObject(item));
}
errCode = stepStatement->BindArguments(bindArgs);
if (errCode != E_OK) {
return nullptr;
}
return stepStatement;
}
int SqliteConnection::EndStepQuery()
{
return stepStatement->ResetStatementAndClearBindings();
}
int SqliteConnection::ChangeEncryptKey(const std::vector<uint8_t> &newKey)
{
int errCode = sqlite3_rekey(dbHandle, static_cast<const void *>(newKey.data()), newKey.size());
if (errCode != SQLITE_OK) {
LOG_ERROR("SqliteConnection ChangeEncryptKey fail, err = %{public}d", errCode);
return SQLiteError::ErrNo(errCode);
}
errCode = statement.Finalize();
if (errCode != SQLITE_OK) {
return errCode;
}
stepStatement->Finalize();
if (errCode != SQLITE_OK) {
return errCode;
}
return E_OK;
}
void SqliteConnection::LimitPermission(const std::string &dbPath) const
{
struct stat st = { 0 };
if (stat(dbPath.c_str(), &st) == 0) {
if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IRWXO)) != 0) {
int ret = chmod(dbPath.c_str(), st.st_mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
if (ret != 0) {
LOG_ERROR("SqliteConnection LimitPermission chmod fail, err = %{public}d", errno);
}
}
} else {
LOG_ERROR("SqliteConnection LimitPermission stat fail, err = %{public}d", errno);
}
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_SQLITE_CONNECTION_H
#define NATIVE_RDB_SQLITE_CONNECTION_H
#include <vector>
#include "sqlite3sym.h"
#include "sqlite_config.h"
#include "sqlite_statement.h"
#include "value_object.h"
namespace OHOS {
namespace NativeRdb {
class SqliteConnection {
public:
static SqliteConnection *Open(const SqliteConfig &config, bool isWriteConnection, int &errCode);
~SqliteConnection();
bool IsWriteConnection() const;
int Prepare(const std::string &sql, bool &outIsReadOnly);
int ExecuteSql(const std::string &sql, const std::vector<ValueObject> &bindArgs = std::vector<ValueObject>());
int ExecuteForChangedRowCount(int &changedRows, const std::string &sql, const std::vector<ValueObject> &bindArgs);
int ExecuteForLastInsertedRowId(
int64_t &outRowId, const std::string &sql, const std::vector<ValueObject> &bindArgs);
int ExecuteGetLong(int64_t &outValue, const std::string &sql,
const std::vector<ValueObject> &bindArgs = std::vector<ValueObject>());
int ExecuteGetString(std::string &outValue, const std::string &sql,
const std::vector<ValueObject> &bindArgs = std::vector<ValueObject>());
std::shared_ptr<SqliteStatement> BeginStepQuery(
int &errCode, const std::string &sql, const std::vector<std::string> &selectionArgs);
int EndStepQuery();
int ChangeEncryptKey(const std::vector<uint8_t> &newKey);
private:
explicit SqliteConnection(bool isWriteConnection);
int InnerOpen(const SqliteConfig &config);
int Config(const SqliteConfig &config);
int SetPageSize();
int SetEncryptKey(const std::vector<uint8_t> &encryptKey);
int SetJournalMode(const std::string &journalMode);
int SetJournalSizeLimit();
int SetAutoCheckpoint();
int SetWalSyncMode();
int PrepareAndBind(const std::string &sql, const std::vector<ValueObject> &bindArgs);
void LimitPermission(const std::string &dbPath) const;
sqlite3 *dbHandle;
bool isWriteConnection;
bool isReadOnly;
SqliteStatement statement;
std::shared_ptr<SqliteStatement> stepStatement;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,226 @@
/*
* Copyright (c) 2021 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 "sqlite_connection_pool.h"
#include "logger.h"
#include "rdb_errno.h"
#include "sqlite_global_config.h"
namespace OHOS {
namespace NativeRdb {
SqliteConnectionPool *SqliteConnectionPool::Create(const RdbStoreConfig &storeConfig, int &errCode)
{
auto pool = new SqliteConnectionPool(storeConfig);
errCode = pool->Init();
if (errCode != E_OK) {
delete pool;
return nullptr;
}
return pool;
}
SqliteConnectionPool::SqliteConnectionPool(const RdbStoreConfig &storeConfig)
: config(storeConfig), writeConnection(nullptr), writeConnectionUsed(true), readConnections(),
readConnectionCount(0), idleReadConnectionCount(0)
{
}
int SqliteConnectionPool::Init()
{
int errCode = E_OK;
writeConnection = SqliteConnection::Open(config, true, errCode);
if (writeConnection == nullptr) {
return errCode;
}
InitReadConnectionCount();
for (int i = 0; i < readConnectionCount; i++) {
SqliteConnection *connection = SqliteConnection::Open(config, false, errCode);
if (connection == nullptr) {
CloseAllConnections();
config.ClearEncryptKey();
return errCode;
}
readConnections.push_back(connection);
}
writeConnectionUsed = false;
idleReadConnectionCount = readConnectionCount;
return E_OK;
}
SqliteConnectionPool::~SqliteConnectionPool()
{
config.ClearEncryptKey();
CloseAllConnections();
}
void SqliteConnectionPool::InitReadConnectionCount()
{
if (config.GetStorageMode() == StorageMode::MODE_MEMORY) {
readConnectionCount = 0;
} else if (config.GetJournalMode() == "WAL") {
readConnectionCount = SqliteGlobalConfig::GetReadConnectionCount();
} else {
readConnectionCount = 0;
}
}
void SqliteConnectionPool::CloseAllConnections()
{
if (writeConnection != nullptr) {
delete writeConnection;
}
writeConnection = nullptr;
writeConnectionUsed = true;
for (auto &item : readConnections) {
if (item != nullptr) {
delete item;
item = nullptr;
}
}
readConnections.clear();
idleReadConnectionCount = 0;
}
SqliteConnection *SqliteConnectionPool::AcquireConnection(bool isReadOnly)
{
if (isReadOnly && readConnectionCount != 0) {
return AcquireReadConnection();
} else {
return AcquireWriteConnection();
}
}
void SqliteConnectionPool::ReleaseConnection(SqliteConnection *connection)
{
if (connection == writeConnection) {
ReleaseWriteConnection();
} else {
ReleaseReadConnection(connection);
}
}
SqliteConnection *SqliteConnectionPool::AcquireWriteConnection()
{
std::unique_lock<std::mutex> lock(writeMutex);
writeCondition.wait(lock, [&] { return !writeConnectionUsed; });
writeConnectionUsed = true;
return writeConnection;
}
void SqliteConnectionPool::ReleaseWriteConnection()
{
{
std::unique_lock<std::mutex> lock(writeMutex);
writeConnectionUsed = false;
}
writeCondition.notify_one();
}
SqliteConnection *SqliteConnectionPool::AcquireReadConnection()
{
std::unique_lock<std::mutex> lock(readMutex);
readCondition.wait(lock, [&] { return idleReadConnectionCount > 0; });
SqliteConnection *connection = readConnections.back();
readConnections.pop_back();
idleReadConnectionCount--;
return connection;
}
void SqliteConnectionPool::ReleaseReadConnection(SqliteConnection *connection)
{
{
std::unique_lock<std::mutex> lock(readMutex);
readConnections.push_back(connection);
idleReadConnectionCount++;
}
readCondition.notify_one();
}
int SqliteConnectionPool::ChangeEncryptKey(const std::vector<uint8_t> &newKey)
{
if (newKey.empty()) {
return E_EMPTY_NEW_ENCRYPT_KEY;
}
if (!config.IsEncrypted()) {
return E_CHANGE_UNENCRYPTED_TO_ENCRYPTED;
}
std::unique_lock<std::mutex> writeLock(writeMutex);
if (writeConnectionUsed) {
return E_CHANGE_ENCRYPT_KEY_IN_BUSY;
}
std::unique_lock<std::mutex> readLock(readMutex);
if (idleReadConnectionCount < readConnectionCount) {
return E_CHANGE_ENCRYPT_KEY_IN_BUSY;
}
int errCode = writeConnection->ChangeEncryptKey(newKey);
if (errCode != E_OK) {
return errCode;
}
config.UpdateEncryptKey(newKey);
for (auto &item : readConnections) {
if (item != nullptr) {
delete item;
item = nullptr;
}
}
readConnections.clear();
for (int i = 0; i < readConnectionCount; i++) {
SqliteConnection *connection = SqliteConnection::Open(config, false, errCode);
if (connection == nullptr) {
config.ClearEncryptKey();
CloseAllConnections();
return errCode;
}
readConnections.push_back(connection);
}
return E_OK;
}
int SqliteConnectionPool::ReOpenAvailableReadConnections()
{
std::unique_lock<std::mutex> lock(readMutex);
for (auto &item : readConnections) {
if (item != nullptr) {
delete item;
item = nullptr;
}
}
readConnections.clear();
int errCode = E_OK;
for (int i = 0; i < idleReadConnectionCount; i++) {
SqliteConnection *connection = SqliteConnection::Open(config, false, errCode);
if (connection == nullptr) {
config.ClearEncryptKey();
CloseAllConnections();
return errCode;
}
readConnections.push_back(connection);
}
return errCode;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_SQLITE_CONNECTION_POOL_H
#define NATIVE_RDB_SQLITE_CONNECTION_POOL_H
#include <condition_variable>
#include <mutex>
#include <vector>
#include "rdb_store_config.h"
#include "sqlite_config.h"
#include "sqlite_connection.h"
namespace OHOS {
namespace NativeRdb {
class SqliteConnectionPool {
public:
static SqliteConnectionPool *Create(const RdbStoreConfig &storeConfig, int &errCode);
~SqliteConnectionPool();
SqliteConnection *AcquireConnection(bool isReadOnly);
void ReleaseConnection(SqliteConnection *connection);
int ChangeEncryptKey(const std::vector<uint8_t> &newKey);
int ReOpenAvailableReadConnections();
private:
explicit SqliteConnectionPool(const RdbStoreConfig &storeConfig);
int Init();
void InitReadConnectionCount();
SqliteConnection *AcquireWriteConnection();
void ReleaseWriteConnection();
SqliteConnection *AcquireReadConnection();
void ReleaseReadConnection(SqliteConnection *connection);
void CloseAllConnections();
SqliteConfig config;
SqliteConnection *writeConnection;
std::mutex writeMutex;
std::condition_variable writeCondition;
bool writeConnectionUsed;
std::vector<SqliteConnection *> readConnections;
std::mutex readMutex;
std::condition_variable readCondition;
int readConnectionCount;
int idleReadConnectionCount;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_SQLITE_ERRNO_H
#define NATIVE_RDB_SQLITE_ERRNO_H
namespace OHOS {
namespace NativeRdb {
class SQLiteError {
public:
static int ErrNo(int sqliteErr)
{
return -sqliteErr;
}
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2021 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 "sqlite_global_config.h"
#include "logger.h"
#include "sqlite3sym.h"
namespace OHOS {
namespace NativeRdb {
const int SqliteGlobalConfig::SOFT_HEAP_LIMIT = 8 * 1024 * 1024; /* 8MB */
const bool SqliteGlobalConfig::CALLBACK_LOG_SWITCH = true; /* Sqlite callback log switch */
const int SqliteGlobalConfig::CONNECTION_POOL_SIZE = 4;
const std::string SqliteGlobalConfig::MEMORY_DB_PATH = ":memory:";
const int SqliteGlobalConfig::DB_PAGE_SIZE = 4096;
const std::string SqliteGlobalConfig::DEFAULT_JOURNAL_MODE = "WAL";
const std::string SqliteGlobalConfig::WAL_SYNC_MODE = "FULL";
const int SqliteGlobalConfig::JOURNAL_FILE_SIZE = 524288; /* 512KB */
const int SqliteGlobalConfig::WAL_AUTO_CHECKPOINT = 100; /* 100 pages */
static SqliteGlobalConfig globalConfig;
SqliteGlobalConfig::SqliteGlobalConfig()
{
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
sqlite3_config(SQLITE_CONFIG_LOG, &SqliteLogCallback, CALLBACK_LOG_SWITCH ? reinterpret_cast<void *>(1) : NULL);
sqlite3_soft_heap_limit(SOFT_HEAP_LIMIT);
sqlite3_initialize();
}
SqliteGlobalConfig::~SqliteGlobalConfig()
{
}
void SqliteGlobalConfig::SqliteLogCallback(const void *data, int err, const char *msg)
{
bool verboseLog = (data != nullptr);
auto errType = static_cast<unsigned int>(err);
errType &= 0xFF;
if (errType == 0 || errType == SQLITE_CONSTRAINT || errType == SQLITE_SCHEMA || errType == SQLITE_NOTICE
|| err == SQLITE_WARNING_AUTOINDEX) {
if (verboseLog) {
LOG_INFO("SQLite Error(%{public}d) %{public}s ", err, msg);
}
} else {
LOG_ERROR("SQLite Error(%{public}d) %{public}s", err, msg);
}
}
int SqliteGlobalConfig::GetReadConnectionCount()
{
return CONNECTION_POOL_SIZE - 1;
}
std::string SqliteGlobalConfig::GetMemoryDbPath()
{
return MEMORY_DB_PATH;
}
int SqliteGlobalConfig::GetPageSize()
{
return DB_PAGE_SIZE;
}
std::string SqliteGlobalConfig::GetWalSyncMode()
{
return WAL_SYNC_MODE;
}
int SqliteGlobalConfig::GetJournalFileSize()
{
return JOURNAL_FILE_SIZE;
}
int SqliteGlobalConfig::GetWalAutoCheckpoint()
{
return WAL_AUTO_CHECKPOINT;
}
std::string SqliteGlobalConfig::GetDefaultJournalMode()
{
return DEFAULT_JOURNAL_MODE;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_SQLITE_GLOBAL_CONFIG_H
#define NATIVE_RDB_SQLITE_GLOBAL_CONFIG_H
#include <string>
namespace OHOS {
namespace NativeRdb {
class SqliteGlobalConfig {
public:
SqliteGlobalConfig();
~SqliteGlobalConfig();
static void SqliteLogCallback(const void *data, int err, const char *msg);
static int GetReadConnectionCount();
static std::string GetMemoryDbPath();
static int GetPageSize();
static std::string GetWalSyncMode();
static int GetJournalFileSize();
static int GetWalAutoCheckpoint();
static std::string GetDefaultJournalMode();
private:
static const int SOFT_HEAP_LIMIT;
static const bool CALLBACK_LOG_SWITCH;
static const int CONNECTION_POOL_SIZE;
static const std::string MEMORY_DB_PATH;
static const int DB_PAGE_SIZE;
static const std::string DEFAULT_JOURNAL_MODE;
static const std::string WAL_SYNC_MODE;
static const int JOURNAL_FILE_SIZE;
static const int WAL_AUTO_CHECKPOINT;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2021 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 "sqlite_sql_builder.h"
#include "rdb_errno.h"
namespace OHOS {
namespace NativeRdb {
int SqliteSqlBuilder::BuildQueryString(bool distinct, const std::string &table,
const std::vector<std::string> &columns, const std::string &where, const std::string &groupBy,
const std::string &having, const std::string &orderBy, const std::string &limit, std::string &outSql)
{
if (groupBy.empty() == true && having.empty() == false) {
return E_HAVING_CLAUSE_NOT_IN_GROUP_BY;
}
if (table.empty()) {
return E_EMPTY_TABLE_NAME;
}
std::stringstream sql;
sql << "SELECT ";
if (distinct) {
sql << "DISTINCT ";
}
AppendColumns(sql, columns);
sql << "FROM " << table;
AppendClause(sql, " WHERE ", where);
AppendClause(sql, " GROUP BY ", groupBy);
AppendClause(sql, " HAVING ", having);
AppendClause(sql, " ORDER BY ", orderBy);
AppendClause(sql, " LIMIT ", limit);
outSql = sql.str();
return E_OK;
}
void SqliteSqlBuilder::AppendClause(std::stringstream &sql, const std::string &name, const std::string &clause)
{
if (clause.empty()) {
return;
}
sql << name << clause;
}
void SqliteSqlBuilder::AppendColumns(std::stringstream &sql, const std::vector<std::string> &columns)
{
if (columns.empty()) {
sql << "* ";
return;
}
bool isFirst = true;
for (auto &iter : columns) {
if (iter.empty()) {
continue;
}
if (isFirst) {
isFirst = false;
} else {
sql << ", ";
}
sql << iter;
}
sql << ' ';
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_SQLITE_SQL_BUILDER_H
#define NATIVE_RDB_SQLITE_SQL_BUILDER_H
#include <map>
#include <sstream>
#include <string>
#include <vector>
namespace OHOS {
namespace NativeRdb {
class SqliteSqlBuilder {
public:
static int BuildQueryString(bool distinct, const std::string &table, const std::vector<std::string> &columns,
const std::string &where, const std::string &groupBy, const std::string &having, const std::string &orderBy,
const std::string &limit, std::string &outSql);
private:
static void AppendClause(std::stringstream &sql, const std::string &name, const std::string &clause);
static void AppendColumns(std::stringstream &sql, const std::vector<std::string> &columns);
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,344 @@
/*
* Copyright (c) 2021 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 "sqlite_statement.h"
#include "logger.h"
#include "rdb_errno.h"
#include "sqlite_errno.h"
namespace OHOS {
namespace NativeRdb {
SqliteStatement::SqliteStatement() : sql(""), stmtHandle(nullptr), readOnly(false), columnCount(0), numParameters(0)
{
}
SqliteStatement::~SqliteStatement()
{
Finalize();
}
int SqliteStatement::Prepare(sqlite3 *dbHandle, const std::string &newSql)
{
if (sql.compare(newSql) == 0) {
return E_OK;
}
// prepare the new sqlite3_stmt
sqlite3_stmt *stmt = nullptr;
int errCode = sqlite3_prepare_v2(dbHandle, newSql.c_str(), newSql.length(), &stmt, nullptr);
if (errCode != SQLITE_OK) {
LOG_ERROR("SqliteStatement::Prepare prepare failed err = %{public}d", errCode);
if (stmt != nullptr) {
sqlite3_finalize(stmt);
}
return SQLiteError::ErrNo(errCode);
}
Finalize(); // finalize the old
sql = newSql;
stmtHandle = stmt;
readOnly = (sqlite3_stmt_readonly(stmtHandle) != 0) ? true : false;
columnCount = sqlite3_column_count(stmtHandle);
numParameters = sqlite3_bind_parameter_count(stmtHandle);
return E_OK;
}
int SqliteStatement::Finalize()
{
if (stmtHandle == nullptr) {
return E_OK;
}
int errCode = sqlite3_finalize(stmtHandle);
stmtHandle = nullptr;
sql = "";
readOnly = false;
columnCount = 0;
numParameters = 0;
if (errCode != SQLITE_OK) {
LOG_ERROR("SqliteStatement::Finalize failed err = %{public}d", errCode);
return SQLiteError::ErrNo(errCode);
}
return E_OK;
}
int SqliteStatement::BindArguments(const std::vector<ValueObject> &bindArgs) const
{
int count = bindArgs.size();
if (count != numParameters) {
return E_INVLAID_BIND_ARGS_COUNT;
}
if (count == 0) {
return E_OK;
}
return InnerBindArguments(bindArgs);
}
int SqliteStatement::InnerBindArguments(const std::vector<ValueObject> &bindArgs) const
{
int index = 1;
int errCode;
for (auto arg : bindArgs) {
switch (arg.GetType()) {
case ValueObjectType::TYPE_NULL: {
errCode = sqlite3_bind_null(stmtHandle, index);
break;
}
case ValueObjectType::TYPE_INT: {
int64_t value = 0;
arg.GetLong(value);
errCode = sqlite3_bind_int64(stmtHandle, index, value);
break;
}
case ValueObjectType::TYPE_DOUBLE: {
double doubleVal = 0;
arg.GetDouble(doubleVal);
errCode = sqlite3_bind_double(stmtHandle, index, doubleVal);
break;
}
case ValueObjectType::TYPE_BLOB: {
std::vector<uint8_t> blob;
arg.GetBlob(blob);
errCode = sqlite3_bind_blob(
stmtHandle, index, static_cast<const void *>(blob.data()), blob.size(), SQLITE_TRANSIENT);
break;
}
case ValueObjectType::TYPE_BOOL: {
bool boolVal = false;
arg.GetBool(boolVal);
errCode = sqlite3_bind_int64(stmtHandle, index, boolVal ? 1 : 0);
break;
}
default: {
std::string str;
arg.GetString(str);
errCode = sqlite3_bind_text(stmtHandle, index, str.c_str(), str.length(), SQLITE_TRANSIENT);
break;
}
}
if (errCode != SQLITE_OK) {
LOG_ERROR("SqliteStatement BindArguments err = %{public}d", errCode);
return SQLiteError::ErrNo(errCode);
}
index++;
}
return E_OK;
}
int SqliteStatement::ResetStatementAndClearBindings() const
{
if (stmtHandle == nullptr) {
return E_OK;
}
int errCode = sqlite3_reset(stmtHandle);
if (errCode != SQLITE_OK) {
LOG_ERROR("Reset statement failed. %{public}d", errCode);
return SQLiteError::ErrNo(errCode);
}
errCode = sqlite3_clear_bindings(stmtHandle);
if (errCode != SQLITE_OK) {
LOG_ERROR("Reset clear bindings failed. %{public}d", errCode);
return SQLiteError::ErrNo(errCode);
}
return E_OK;
}
int SqliteStatement::Step() const
{
int errCode = sqlite3_step(stmtHandle);
return errCode;
}
int SqliteStatement::GetColumnCount(int &count) const
{
if (stmtHandle == nullptr) {
return E_INVALID_STATEMENT;
}
count = columnCount;
return E_OK;
}
int SqliteStatement::GetColumnName(int index, std::string &columnName) const
{
if (stmtHandle == nullptr) {
return E_INVALID_STATEMENT;
}
if (index > columnCount) {
return E_INVALID_COLUMN_INDEX;
}
const char *name = sqlite3_column_name(stmtHandle, index);
if (name == nullptr) {
return E_ERROR;
}
columnName = std::string(name);
return E_OK;
}
int SqliteStatement::GetColumnType(int index, int &columnType) const
{
if (stmtHandle == nullptr) {
return E_INVALID_STATEMENT;
}
if (index > columnCount) {
return E_INVALID_COLUMN_INDEX;
}
int type = sqlite3_column_type(stmtHandle, index);
switch (type) {
case SQLITE_INTEGER:
case SQLITE_FLOAT:
case SQLITE_BLOB:
case SQLITE_NULL:
case SQLITE_TEXT:
columnType = type;
return E_OK;
default:
return E_ERROR;
}
}
int SqliteStatement::GetColumnBlob(int index, std::vector<uint8_t> &value) const
{
if (stmtHandle == nullptr) {
return E_INVALID_STATEMENT;
}
if (index > columnCount) {
return E_INVALID_COLUMN_INDEX;
}
int type = sqlite3_column_type(stmtHandle, index);
if (type != SQLITE_BLOB && type != SQLITE_TEXT) {
return E_INVALID_COLUMN_TYPE;
}
int size = sqlite3_column_bytes(stmtHandle, index);
auto blob = static_cast<const uint8_t *>(sqlite3_column_blob(stmtHandle, index));
if (size == 0 || blob == nullptr) {
value.resize(0);
} else {
value.resize(size);
value.assign(blob, blob + size);
}
return E_OK;
}
int SqliteStatement::GetColumnString(int index, std::string &value) const
{
if (stmtHandle == nullptr) {
return E_INVALID_STATEMENT;
}
if (index > columnCount) {
return E_INVALID_COLUMN_INDEX;
}
int type = sqlite3_column_type(stmtHandle, index);
if (type == SQLITE_TEXT) {
auto val = reinterpret_cast<const char *>(sqlite3_column_text(stmtHandle, index));
value = (val == nullptr) ? "" : val;
} else if (type == SQLITE_INTEGER) {
int64_t val = sqlite3_column_int64(stmtHandle, index);
value = std::to_string(val);
} else if (type == SQLITE_FLOAT) {
double val = sqlite3_column_double(stmtHandle, index);
value = std::to_string(val);
} else if (type == SQLITE_NULL) {
value = "";
} else if (type == SQLITE_BLOB) {
return E_INVALID_COLUMN_TYPE;
} else {
return E_ERROR;
}
return E_OK;
}
int SqliteStatement::GetColumnLong(int index, int64_t &value) const
{
if (stmtHandle == nullptr) {
return E_INVALID_STATEMENT;
}
if (index > columnCount) {
return E_INVALID_COLUMN_INDEX;
}
int type = sqlite3_column_type(stmtHandle, index);
if (type == SQLITE_INTEGER) {
value = sqlite3_column_int64(stmtHandle, index);
} else if (type == SQLITE_TEXT) {
auto val = reinterpret_cast<const char *>(sqlite3_column_text(stmtHandle, index));
value = (val == nullptr) ? 0 : std::stoll(val);
} else if (type == SQLITE_FLOAT) {
double val = sqlite3_column_double(stmtHandle, index);
value = static_cast<int64_t>(val);
} else if (type == SQLITE_NULL) {
value = 0;
} else if (type == SQLITE_BLOB) {
return E_INVALID_COLUMN_TYPE;
} else {
return E_ERROR;
}
return E_OK;
}
int SqliteStatement::GetColumnDouble(int index, double &value) const
{
if (stmtHandle == nullptr) {
return E_INVALID_STATEMENT;
}
if (index > columnCount) {
return E_INVALID_COLUMN_INDEX;
}
int type = sqlite3_column_type(stmtHandle, index);
if (type == SQLITE_FLOAT) {
value = sqlite3_column_double(stmtHandle, index);
} else if (type == SQLITE_INTEGER) {
int64_t val = sqlite3_column_int64(stmtHandle, index);
value = static_cast<double>(val);
} else if (type == SQLITE_TEXT) {
auto val = reinterpret_cast<const char *>(sqlite3_column_text(stmtHandle, index));
value = (val == nullptr) ? 0.0 : std::stod(val);
} else if (type == SQLITE_NULL) {
value = 0.0;
} else if (type == SQLITE_BLOB) {
return E_INVALID_COLUMN_TYPE;
} else {
return E_ERROR;
}
return E_OK;
}
bool SqliteStatement::IsReadOnly() const
{
return readOnly;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_SQLITE_STATEMENT_H
#define NATIVE_RDB_SQLITE_STATEMENT_H
#include <vector>
#include "sqlite3sym.h"
#include "value_object.h"
namespace OHOS {
namespace NativeRdb {
class SqliteStatement {
public:
SqliteStatement();
~SqliteStatement();
int Prepare(sqlite3 *dbHandle, const std::string &sql);
int Finalize();
int BindArguments(const std::vector<ValueObject> &bindArgs) const;
int ResetStatementAndClearBindings() const;
int Step() const;
int GetColumnCount(int &count) const;
int GetColumnName(int index, std::string &columnName) const;
int GetColumnType(int index, int &columnType) const; // 0: fail, >0: type
int GetColumnBlob(int index, std::vector<uint8_t> &value) const;
int GetColumnString(int index, std::string &value) const; // fail ??
int GetColumnLong(int index, int64_t &value) const;
int GetColumnDouble(int index, double &value) const; // fail ??
bool IsReadOnly() const;
private:
int InnerBindArguments(const std::vector<ValueObject> &bindArgs) const;
std::string sql;
sqlite3_stmt *stmtHandle;
bool readOnly;
int columnCount;
int numParameters;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2021 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 "sqlite_utils.h"
#include "rdb_errno.h"
namespace OHOS {
namespace NativeRdb {
const int SqliteUtils::STATEMENT_SELECT = 1;
const int SqliteUtils::STATEMENT_UPDATE = 2;
const int SqliteUtils::STATEMENT_ATTACH = 3;
const int SqliteUtils::STATEMENT_DETACH = 4;
const int SqliteUtils::STATEMENT_BEGIN = 5;
const int SqliteUtils::STATEMENT_COMMIT = 6;
const int SqliteUtils::STATEMENT_ROLLBACK = 7;
const int SqliteUtils::STATEMENT_PRAGMA = 8;
const int SqliteUtils::STATEMENT_DDL = 9;
const int SqliteUtils::STATEMENT_OTHER = 99;
const std::map<std::string, int> SqliteUtils::SQL_TYPE_MAP = {
{ "SEL", SqliteUtils::STATEMENT_SELECT },
{ "INS", SqliteUtils::STATEMENT_UPDATE },
{ "UPD", SqliteUtils::STATEMENT_UPDATE },
{ "REP", SqliteUtils::STATEMENT_UPDATE },
{ "DEL", SqliteUtils::STATEMENT_UPDATE },
{ "ATT", SqliteUtils::STATEMENT_ATTACH },
{ "DET", SqliteUtils::STATEMENT_DETACH },
{ "COM", SqliteUtils::STATEMENT_COMMIT },
{ "END", SqliteUtils::STATEMENT_COMMIT },
{ "ROL", SqliteUtils::STATEMENT_ROLLBACK },
{ "BEG", SqliteUtils::STATEMENT_BEGIN },
{ "PRA", SqliteUtils::STATEMENT_PRAGMA },
{ "CRE", SqliteUtils::STATEMENT_DDL },
{ "DRO", SqliteUtils::STATEMENT_DDL },
{ "ALT", SqliteUtils::STATEMENT_DDL },
};
int SqliteUtils::GetSqlStatementType(const std::string &sql)
{
std::string sqlStr = sql;
/* the sql string length less than 3 can not be any type sql */
if (sqlStr.length() < 3) {
return STATEMENT_OTHER;
}
/* analyze the sql type through first 3 character */
std::string prefixSql = StrToUpper(sqlStr.substr(0, 3));
auto iter = SQL_TYPE_MAP.find(prefixSql);
if (iter != SQL_TYPE_MAP.end()) {
return iter->second;
}
return STATEMENT_OTHER;
}
std::string SqliteUtils::StrToUpper(std::string s)
{
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); });
return s;
}
bool SqliteUtils::IsSqlReadOnly(int sqlType)
{
return (sqlType == STATEMENT_SELECT) ? true : false;
}
bool SqliteUtils::IsSpecial(int sqlType)
{
if (sqlType == STATEMENT_BEGIN || sqlType == STATEMENT_COMMIT || sqlType == STATEMENT_ROLLBACK) {
return true;
}
return false;
}
const std::string SqliteUtils::ON_CONFLICT_CLAUSE[] = { "", " OR ROLLBACK", " OR ABORT", " OR FAIL", " OR IGNORE",
" OR REPLACE" };
int SqliteUtils::GetConflictClause(int conflictResolution, std::string &conflictClause)
{
if (conflictResolution < 0 || conflictResolution >= CONFLICT_CLAUSE_COUNT) {
return E_INVALID_CONFLICT_FLAG;
}
conflictClause = ON_CONFLICT_CLAUSE[conflictResolution];
return E_OK;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_SQLITE_UTILS_H
#define NATIVE_RDB_SQLITE_UTILS_H
#include <map>
#include <string>
namespace OHOS {
namespace NativeRdb {
class SqliteUtils {
public:
static const int STATEMENT_SELECT;
static const int STATEMENT_UPDATE;
static const int STATEMENT_ATTACH;
static const int STATEMENT_DETACH;
static const int STATEMENT_BEGIN;
static const int STATEMENT_COMMIT;
static const int STATEMENT_ROLLBACK;
static const int STATEMENT_PRAGMA;
static const int STATEMENT_DDL;
static const int STATEMENT_OTHER;
static const int CONFLICT_CLAUSE_COUNT = 6;
static int GetSqlStatementType(const std::string &sql);
static bool IsSqlReadOnly(int sqlType);
static bool IsSpecial(int sqlType);
static int GetConflictClause(int conflictResolution, std::string &conflictClause);
static std::string StrToUpper(std::string s);
private:
static const std::map<std::string, int> SQL_TYPE_MAP;
static const std::string ON_CONFLICT_CLAUSE[CONFLICT_CLAUSE_COUNT];
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,384 @@
/*
* Copyright (c) 2021 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 "step_result_set.h"
#include <unistd.h>
#include "logger.h"
#include "rdb_errno.h"
#include "sqlite3sym.h"
#include "sqlite_errno.h"
namespace OHOS {
namespace NativeRdb {
StepResultSet::StepResultSet(
std::shared_ptr<RdbStoreImpl> rdb, const std::string &sql, const std::vector<std::string> &selectionArgs)
: rdb(rdb), sql(sql), selectionArgs(selectionArgs), pos(INIT_POS), isAfterLast(false), isClosed(false),
sqliteStatement(nullptr)
{
}
StepResultSet::~StepResultSet()
{
Close();
}
int StepResultSet::GetAllColumnNames(std::vector<std::string> &columnNames)
{
int errCode = PrepareStep();
if (errCode) {
return errCode;
}
int columnCount = 0;
errCode = sqliteStatement->GetColumnCount(columnCount);
if (errCode) {
return errCode;
}
columnNames.clear();
for (int i = 0; i < columnCount; i++) {
std::string columnName;
errCode = sqliteStatement->GetColumnName(i, columnName);
if (errCode) {
columnNames.clear();
return errCode;
}
columnNames.push_back(columnName);
}
return E_OK;
}
int StepResultSet::GetColumnCount(int &count)
{
int errCode = PrepareStep();
if (errCode) {
return errCode;
}
errCode = sqliteStatement->GetColumnCount(count);
return errCode;
}
int StepResultSet::GetColumnTypeForIndex(int columnIndex, ColumnType &columnType) const
{
if (pos == INIT_POS) {
return E_STEP_RESULT_QUERY_NOT_EXECUTED;
}
int sqliteType;
int errCode = sqliteStatement->GetColumnType(columnIndex, sqliteType);
if (errCode) {
return errCode;
}
switch (sqliteType) {
case SQLITE_INTEGER:
columnType = ColumnType::TYPE_INTEGER;
break;
case SQLITE_FLOAT:
columnType = ColumnType::TYPE_FLOAT;
break;
case SQLITE_BLOB:
columnType = ColumnType::TYPE_BLOB;
break;
case SQLITE_NULL:
columnType = ColumnType::TYPE_NULL;
break;
default:
columnType = ColumnType::TYPE_STRING;
}
return E_OK;
}
int StepResultSet::GetColumnIndexForName(const std::string &columnName, int &columnIndex)
{
int errCode = PrepareStep();
if (errCode) {
return errCode;
}
int columnCount = 0;
errCode = sqliteStatement->GetColumnCount(columnCount);
if (errCode) {
return errCode;
}
for (int i = 0; i < columnCount; i++) {
std::string name;
errCode = sqliteStatement->GetColumnName(i, name);
if (errCode) {
return errCode;
}
if (columnName.compare(name) == 0) {
columnIndex = i;
return E_OK;
}
}
return E_INVALID_COLUMN_NAME;
}
int StepResultSet::GetColumnNameForIndex(int columnIndex, std::string &columnName)
{
int errCode = PrepareStep();
if (errCode) {
return errCode;
}
errCode = sqliteStatement->GetColumnName(columnIndex, columnName);
return errCode;
}
int StepResultSet::GetRowCount(int &count) const
{
LOG_ERROR("GetRowCount is not supported by StepResultSet");
return E_NOT_SUPPORTED_BY_STEP_RESULT_SET;
}
int StepResultSet::GetRowIndex(int &position) const
{
position = pos;
return E_OK;
}
int StepResultSet::GoTo(int offset)
{
LOG_ERROR("Move is not supported by StepResultSet");
return E_NOT_SUPPORTED_BY_STEP_RESULT_SET;
}
int StepResultSet::GoToRow(int position)
{
LOG_ERROR("GoToRow is not supported by StepResultSet");
return E_NOT_SUPPORTED_BY_STEP_RESULT_SET;
}
int StepResultSet::GoToFirstRow()
{
if (pos == INIT_POS) {
return GoToNextRow();
}
LOG_ERROR("GoToFirstRow is not supported by StepResultSet");
return E_NOT_SUPPORTED_BY_STEP_RESULT_SET;
}
int StepResultSet::GoToLastRow()
{
LOG_ERROR("GoToLastRow is not supported by StepResultSet");
return E_NOT_SUPPORTED_BY_STEP_RESULT_SET;
}
int StepResultSet::GoToNextRow()
{
if (isAfterLast) {
return E_STEP_RESULT_IS_AFTER_LASET;
}
int errCode = PrepareStep();
if (errCode) {
return errCode;
}
int retryCount = 0;
errCode = sqliteStatement->Step();
while (errCode == SQLITE_LOCKED || errCode == SQLITE_BUSY) {
// The table is locked, retry
if (retryCount > STEP_QUERY_RETRY_MAX_TIMES) {
LOG_ERROR("StepResultSet::GoToNextRow retrycount exceeded");
return E_STEP_RESULT_QUERY_EXCEEDED;
} else {
// Sleep to give the thread holding the lock a chance to finish
usleep(STEP_QUERY_RETRY_INTERVAL);
errCode = sqliteStatement->Step();
retryCount++;
}
}
if (errCode == SQLITE_ROW) {
pos++;
return E_OK;
} else if (errCode == SQLITE_DONE) {
isAfterLast = true;
FinishStep();
return E_STEP_RESULT_IS_AFTER_LASET;
} else {
LOG_ERROR("StepResultSet::GoToNextRow step err = %{public}d", errCode);
FinishStep();
return SQLiteError::ErrNo(errCode);
}
}
int StepResultSet::GoToPreviousRow()
{
LOG_ERROR("GoToPreviousRow is not supported by StepResultSet");
return E_NOT_SUPPORTED_BY_STEP_RESULT_SET;
}
int StepResultSet::IsEnded(bool &result) const
{
result = isAfterLast;
return E_OK;
}
int StepResultSet::IsStarted(bool &result) const
{
result = (pos == INIT_POS);
return E_OK;
}
int StepResultSet::IsAtFirstRow(bool &result) const
{
result = (pos == 0);
return E_OK;
}
int StepResultSet::IsAtLastRow(bool &result) const
{
LOG_ERROR("IsAtLastRow is not supported by StepResultSet");
return E_NOT_SUPPORTED_BY_STEP_RESULT_SET;
}
int StepResultSet::GetBlob(int columnIndex, std::vector<uint8_t> &blob) const
{
if (pos == INIT_POS) {
return E_STEP_RESULT_QUERY_NOT_EXECUTED;
}
return sqliteStatement->GetColumnBlob(columnIndex, blob);
}
int StepResultSet::GetString(int columnIndex, std::string &value) const
{
if (pos == INIT_POS) {
return E_STEP_RESULT_QUERY_NOT_EXECUTED;
}
return sqliteStatement->GetColumnString(columnIndex, value);
}
int StepResultSet::GetInt(int columnIndex, int &value) const
{
if (pos == INIT_POS) {
return E_STEP_RESULT_QUERY_NOT_EXECUTED;
}
int64_t columnValue;
int errCode = sqliteStatement->GetColumnLong(columnIndex, columnValue);
if (errCode != E_OK) {
return errCode;
}
value = static_cast<int>(columnValue);
return E_OK;
}
int StepResultSet::GetLong(int columnIndex, int64_t &value) const
{
if (pos == INIT_POS) {
return E_STEP_RESULT_QUERY_NOT_EXECUTED;
}
return sqliteStatement->GetColumnLong(columnIndex, value);
}
int StepResultSet::GetDouble(int columnIndex, double &value) const
{
if (pos == INIT_POS) {
return E_STEP_RESULT_QUERY_NOT_EXECUTED;
}
return sqliteStatement->GetColumnDouble(columnIndex, value);
}
int StepResultSet::IsColumnNull(int columnIndex, bool &isNull) const
{
ColumnType columnType;
int errCode = GetColumnTypeForIndex(columnIndex, columnType);
if (errCode != E_OK) {
return errCode;
}
isNull = (columnType == ColumnType::TYPE_NULL);
return E_OK;
}
bool StepResultSet::IsClosed() const
{
return isClosed;
}
int StepResultSet::Close()
{
if (isClosed) {
return E_OK;
}
isClosed = true;
int errCode = FinishStep();
rdb = nullptr;
return errCode;
}
int StepResultSet::CheckSession()
{
if (std::this_thread::get_id() != tid) {
LOG_ERROR("StepResultSet is passed cross threads!");
return E_STEP_RESULT_SET_CROSS_THREADS;
}
return E_OK;
}
int StepResultSet::PrepareStep()
{
if (isClosed) {
return E_STEP_RESULT_CLOSED;
}
if (sqliteStatement != nullptr) {
return CheckSession();
}
int errCode;
sqliteStatement = rdb->BeginStepQuery(errCode, sql, selectionArgs);
if (sqliteStatement == nullptr) {
rdb->EndStepQuery();
return errCode;
}
tid = std::this_thread::get_id();
return E_OK;
}
int StepResultSet::FinishStep()
{
int errCode = CheckSession();
if (errCode != E_OK) {
return errCode;
}
if (sqliteStatement == nullptr) {
return E_OK;
}
sqliteStatement = nullptr;
pos = INIT_POS;
errCode = rdb->EndStepQuery();
if (errCode != E_OK) {
LOG_ERROR("StepResultSet::FinishStep err = %{public}d", errCode);
}
return errCode;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_STEP_RESULT_SET_H
#define NATIVE_RDB_STEP_RESULT_SET_H
#include <memory>
#include <thread>
#include <vector>
#include "rdb_store_impl.h"
#include "result_set.h"
#include "sqlite_statement.h"
namespace OHOS {
namespace NativeRdb {
class StepResultSet : public ResultSet {
public:
StepResultSet(
std::shared_ptr<RdbStoreImpl> rdb, const std::string &sql, const std::vector<std::string> &selectionArgs);
~StepResultSet() override;
int GetAllColumnNames(std::vector<std::string> &columnNames) override;
int GetColumnCount(int &count) override;
int GetColumnTypeForIndex(int columnIndex, ColumnType &columnType) const override;
int GetColumnIndexForName(const std::string &columnName, int &columnIndex) override;
int GetColumnNameForIndex(int columnIndex, std::string &columnName) override;
int GetRowCount(int &count) const override;
int GetRowIndex(int &position) const override;
int GoTo(int offset) override;
int GoToRow(int position) override;
int GoToFirstRow() override;
int GoToLastRow() override;
int GoToNextRow() override;
int GoToPreviousRow() override;
int IsEnded(bool &result) const override;
int IsStarted(bool &result) const override;
int IsAtFirstRow(bool &result) const override;
int IsAtLastRow(bool &result) const override;
int GetBlob(int columnIndex, std::vector<uint8_t> &blob) const override;
int GetString(int columnIndex, std::string &value) const override;
int GetInt(int columnIndex, int &value) const override;
int GetLong(int columnIndex, int64_t &value) const override;
int GetDouble(int columnIndex, double &value) const override;
int IsColumnNull(int columnIndex, bool &isNull) const override;
bool IsClosed() const override;
int Close() override;
private:
int CheckSession();
int PrepareStep();
int FinishStep();
std::shared_ptr<RdbStoreImpl> rdb;
std::string sql;
std::vector<std::string> selectionArgs;
int pos;
bool isAfterLast;
bool isClosed;
std::thread::id tid;
std::shared_ptr<SqliteStatement> sqliteStatement;
static const int INIT_POS = -1;
// Max times of retrying step query
static const int STEP_QUERY_RETRY_MAX_TIMES = 50;
// Interval of retrying step query in millisecond
static const int STEP_QUERY_RETRY_INTERVAL = 1000;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,267 @@
/*
* Copyright (c) 2021 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 "store_session.h"
#include "logger.h"
#include "rdb_errno.h"
#include "sqlite_utils.h"
namespace OHOS {
namespace NativeRdb {
StoreSession::StoreSession(SqliteConnectionPool &connectionPool)
: connectionPool(connectionPool), connection(nullptr), connectionUseCount(0), isInStepQuery(false),
transactionStack()
{
}
StoreSession::~StoreSession()
{
}
void StoreSession::AcquireConnection(bool isReadOnly)
{
if (connection == nullptr) {
connection = connectionPool.AcquireConnection(isReadOnly);
}
connectionUseCount += 1;
}
void StoreSession::ReleaseConnection()
{
if ((connection == nullptr) || (connectionUseCount <= 0)) {
LOG_ERROR("SQLiteSession ReleaseConnection repeated release");
return;
}
if (--connectionUseCount == 0) {
connectionPool.ReleaseConnection(connection);
connection = nullptr;
}
}
int StoreSession::BeginExecuteSql(const std::string &sql)
{
int type = SqliteUtils::GetSqlStatementType(sql);
if (SqliteUtils::IsSpecial(type)) {
return E_TRANSACTION_IN_EXECUTE;
}
bool assumeReadOnly = SqliteUtils::IsSqlReadOnly(type);
bool isReadOnly = false;
AcquireConnection(assumeReadOnly);
int errCode = connection->Prepare(sql, isReadOnly);
if (errCode != 0) {
ReleaseConnection();
return errCode;
}
if (isReadOnly == connection->IsWriteConnection()) {
ReleaseConnection();
AcquireConnection(isReadOnly);
if (!isReadOnly && !connection->IsWriteConnection()) {
LOG_ERROR("StoreSession BeginExecutea : read connection can not execute write operation");
ReleaseConnection();
return E_EXECUTE_WRITE_IN_READ_CONNECTION;
}
}
return E_OK;
}
int StoreSession::ExecuteSql(const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = BeginExecuteSql(sql);
if (errCode != 0) {
return errCode;
}
errCode = connection->ExecuteSql(sql, bindArgs);
ReleaseConnection();
return errCode;
}
int StoreSession::ExecuteForChangedRowCount(
int &changedRows, const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = BeginExecuteSql(sql);
if (errCode != 0) {
return errCode;
}
errCode = connection->ExecuteForChangedRowCount(changedRows, sql, bindArgs);
ReleaseConnection();
return errCode;
}
int StoreSession::ExecuteForLastInsertedRowId(
int64_t &outRowId, const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = BeginExecuteSql(sql);
if (errCode != 0) {
return errCode;
}
errCode = connection->ExecuteForLastInsertedRowId(outRowId, sql, bindArgs);
ReleaseConnection();
return errCode;
}
int StoreSession::ExecuteGetLong(int64_t &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = BeginExecuteSql(sql);
if (errCode != 0) {
return errCode;
}
errCode = connection->ExecuteGetLong(outValue, sql, bindArgs);
ReleaseConnection();
return errCode;
}
int StoreSession::ExecuteGetString(
std::string &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs)
{
int errCode = BeginExecuteSql(sql);
if (errCode != 0) {
return errCode;
}
errCode = connection->ExecuteGetString(outValue, sql, bindArgs);
ReleaseConnection();
return errCode;
}
int StoreSession::BeginTransaction()
{
if (transactionStack.empty()) {
AcquireConnection(false);
if (!connection->IsWriteConnection()) {
LOG_ERROR("StoreSession BeginExecutea : read connection can not begin transaction");
ReleaseConnection();
return E_BEGIN_TRANSACTION_IN_READ_CONNECTION;
}
int errCode = connection->ExecuteSql("BEGIN EXCLUSIVE;");
if (errCode != E_OK) {
ReleaseConnection();
return errCode;
}
}
Transaction transaction;
transactionStack.push(transaction);
return E_OK;
}
int StoreSession::MarkAsCommit()
{
if (transactionStack.empty()) {
return E_NO_TRANSACTION_IN_SESSION;
}
transactionStack.top().SetMarkedSuccessful(true);
return E_OK;
}
int StoreSession::EndTransaction()
{
if (transactionStack.empty()) {
return E_NO_TRANSACTION_IN_SESSION;
}
Transaction transaction = transactionStack.top();
bool isSucceed = transaction.IsAllBeforeSuccessful() && transaction.IsMarkedSuccessful();
transactionStack.pop();
if (!transactionStack.empty()) {
if (!isSucceed) {
transactionStack.top().SetAllBeforeSuccessful(false);
}
} else {
int errCode = connection->ExecuteSql(isSucceed ? "COMMIT;" : "ROLLBACK;");
ReleaseConnection();
return errCode;
}
return E_OK;
}
bool StoreSession::IsInTransaction() const
{
return !transactionStack.empty();
}
std::shared_ptr<SqliteStatement> StoreSession::BeginStepQuery(
int &errCode, const std::string &sql, const std::vector<std::string> &selectionArgs)
{
if (isInStepQuery == true) {
LOG_ERROR("StoreSession BeginStepQuery fail : begin more step query in one session !");
errCode = E_MORE_STEP_QUERY_IN_ONE_SESSION;
return nullptr; // fail,already in
}
if (SqliteUtils::GetSqlStatementType(sql) != SqliteUtils::STATEMENT_SELECT) {
LOG_ERROR("StoreSession BeginStepQuery fail : not select sql !");
errCode = E_EXECUTE_IN_STEP_QUERY;
return nullptr;
}
AcquireConnection(true);
std::shared_ptr<SqliteStatement> statement = connection->BeginStepQuery(errCode, sql, selectionArgs);
if (statement == nullptr) {
ReleaseConnection();
return nullptr;
}
isInStepQuery = true;
return statement;
}
int StoreSession::EndStepQuery()
{
if (isInStepQuery == false) {
return E_OK;
}
int errCode = connection->EndStepQuery();
isInStepQuery = false;
ReleaseConnection();
return errCode;
}
StoreSession::Transaction::Transaction() : isAllBeforeSuccessful(true), isMarkedSuccessful(false)
{
}
StoreSession::Transaction::~Transaction()
{
}
bool StoreSession::Transaction::IsAllBeforeSuccessful() const
{
return isAllBeforeSuccessful;
}
void StoreSession::Transaction::SetAllBeforeSuccessful(bool isAllBeforeSuccessful)
{
this->isAllBeforeSuccessful = isAllBeforeSuccessful;
}
bool StoreSession::Transaction::IsMarkedSuccessful() const
{
return isMarkedSuccessful;
}
void StoreSession::Transaction::SetMarkedSuccessful(bool isMarkedSuccessful)
{
this->isMarkedSuccessful = isMarkedSuccessful;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_RDB_STORE_SESSION_H
#define NATIVE_RDB_RDB_STORE_SESSION_H
#include <memory>
#include <stack>
#include "sqlite_connection.h"
#include "sqlite_connection_pool.h"
#include "value_object.h"
namespace OHOS {
namespace NativeRdb {
class StoreSession {
public:
explicit StoreSession(SqliteConnectionPool &connectionPool);
~StoreSession();
int ExecuteSql(const std::string &sql, const std::vector<ValueObject> &bindArgs);
int ExecuteForChangedRowCount(int &changedRows, const std::string &sql, const std::vector<ValueObject> &bindArgs);
int ExecuteForLastInsertedRowId(
int64_t &outRowId, const std::string &sql, const std::vector<ValueObject> &bindArgs);
int ExecuteGetLong(int64_t &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs);
int ExecuteGetString(std::string &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs);
int BeginTransaction();
int MarkAsCommit();
int EndTransaction();
bool IsInTransaction() const;
std::shared_ptr<SqliteStatement> BeginStepQuery(
int &errCode, const std::string &sql, const std::vector<std::string> &selectionArgs);
int EndStepQuery();
private:
class Transaction {
public:
Transaction();
~Transaction();
bool IsAllBeforeSuccessful() const;
void SetAllBeforeSuccessful(bool isAllBeforeSuccessful);
bool IsMarkedSuccessful() const;
void SetMarkedSuccessful(bool isMarkedSuccessful);
private:
bool isAllBeforeSuccessful;
bool isMarkedSuccessful;
};
void AcquireConnection(bool isReadOnly);
void ReleaseConnection();
int BeginExecuteSql(const std::string &sql);
SqliteConnectionPool &connectionPool;
SqliteConnection *connection;
int connectionUseCount;
bool isInStepQuery;
std::stack<Transaction> transactionStack;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) 2021 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 "value_object.h"
#include "rdb_errno.h"
#include "sqlite_utils.h"
namespace OHOS {
namespace NativeRdb {
ValueObject::ValueObject() : type(ValueObjectType::TYPE_NULL)
{
}
ValueObject::~ValueObject()
{
}
ValueObject::ValueObject(int val) : type(ValueObjectType::TYPE_INT)
{
value = static_cast<int64_t>(val);
}
ValueObject::ValueObject(int64_t val) : type(ValueObjectType::TYPE_INT)
{
value = val;
}
ValueObject::ValueObject(double val) : type(ValueObjectType::TYPE_DOUBLE)
{
value = val;
}
ValueObject::ValueObject(bool val) : type(ValueObjectType::TYPE_BOOL)
{
value = val;
}
ValueObject::ValueObject(const std::string &val) : type(ValueObjectType::TYPE_STRING)
{
value = val;
}
ValueObject::ValueObject(const std::vector<uint8_t> &val) : type(ValueObjectType::TYPE_BLOB)
{
std::vector<uint8_t> blob = val;
value = blob;
}
ValueObjectType ValueObject::GetType() const
{
return type;
}
int ValueObject::GetInt(int &val) const
{
if (type != ValueObjectType::TYPE_INT) {
return E_INVLAID_ONJECT_TYPE;
}
int64_t v = std::get<int64_t>(value);
val = static_cast<int>(v);
return E_OK;
}
int ValueObject::GetLong(int64_t &val) const
{
if (type != ValueObjectType::TYPE_INT) {
return E_INVLAID_ONJECT_TYPE;
}
val = std::get<int64_t>(value);
return E_OK;
}
int ValueObject::GetDouble(double &val) const
{
if (type != ValueObjectType::TYPE_DOUBLE) {
return E_INVLAID_ONJECT_TYPE;
}
val = std::get<double>(value);
return E_OK;
}
int ValueObject::GetBool(bool &val) const
{
if (type != ValueObjectType::TYPE_BOOL) {
return E_INVLAID_ONJECT_TYPE;
}
val = std::get<bool>(value);
return E_OK;
}
int ValueObject::GetString(std::string &val) const
{
if (type != ValueObjectType::TYPE_STRING) {
return E_INVLAID_ONJECT_TYPE;
}
val = std::get<std::string>(value);
return E_OK;
}
int ValueObject::GetBlob(std::vector<uint8_t> &val) const
{
if (type != ValueObjectType::TYPE_BLOB) {
return E_INVLAID_ONJECT_TYPE;
}
val = std::get<std::vector<uint8_t>>(value);
return E_OK;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2021 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 "values_bucket.h"
namespace OHOS {
namespace NativeRdb {
ValuesBucket::ValuesBucket()
{
}
ValuesBucket::~ValuesBucket()
{
}
void ValuesBucket::PutString(const std::string &columnName, const std::string &value)
{
valuesMap.insert(std::make_pair(columnName, ValueObject(value)));
}
void ValuesBucket::PutInt(const std::string &columnName, int value)
{
valuesMap.insert(std::make_pair(columnName, ValueObject(value)));
}
void ValuesBucket::PutLong(const std::string &columnName, int64_t value)
{
valuesMap.insert(std::make_pair(columnName, ValueObject(value)));
}
void ValuesBucket::PutDouble(const std::string &columnName, double value)
{
valuesMap.insert(std::make_pair(columnName, ValueObject(value)));
}
void ValuesBucket::PutBool(const std::string &columnName, bool value)
{
valuesMap.insert(std::make_pair(columnName, ValueObject(value)));
}
void ValuesBucket::PutBlob(const std::string &columnName, const std::vector<uint8_t> &value)
{
valuesMap.insert(std::make_pair(columnName, ValueObject(value)));
}
void ValuesBucket::PutNull(const std::string &columnName)
{
valuesMap.insert(std::make_pair(columnName, ValueObject()));
}
void ValuesBucket::Delete(const std::string &columnName)
{
valuesMap.erase(columnName);
}
void ValuesBucket::Clear()
{
valuesMap.clear();
}
int ValuesBucket::Size() const
{
return valuesMap.size();
}
bool ValuesBucket::IsEmpty() const
{
return valuesMap.empty();
}
bool ValuesBucket::HasColumn(const std::string &columnName) const
{
auto iter = valuesMap.find(columnName);
if (iter == valuesMap.end()) {
return false;
}
return true;
}
bool ValuesBucket::GetObject(const std::string &columnName, ValueObject &value) const
{
auto iter = valuesMap.find(columnName);
if (iter == valuesMap.end()) {
return false;
}
value = iter->second;
return true;
}
void ValuesBucket::GetAll(std::map<std::string, ValueObject> &outValuesMap) const
{
outValuesMap = valuesMap;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -0,0 +1,62 @@
# Copyright (c) 2021 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("//build/test.gni")
module_output_path = "appdatamgr/native_rdb"
###############################################################################
config("module_private_config") {
visibility = [ ":*" ]
include_dirs = [
##"../include/",
"../../../../interfaces/innerkits/native_rdb/include",
]
}
ohos_unittest("NativeRdbTest") {
module_out_path = module_output_path
sources = [
"unittest/rdb_attach_test.cpp",
"unittest/rdb_delete_test.cpp",
"unittest/rdb_encrypt_test.cpp",
"unittest/rdb_execute_test.cpp",
"unittest/rdb_helper_test.cpp",
"unittest/rdb_insert_test.cpp",
"unittest/rdb_open_callback_test.cpp",
"unittest/rdb_store_concurrent_test.cpp",
"unittest/rdb_store_config_test.cpp",
"unittest/rdb_store_interface_test.cpp",
"unittest/rdb_transaction_test.cpp",
"unittest/rdb_update_test.cpp",
"unittest/rdb_upgrade_test.cpp",
]
configs = [ ":module_private_config" ]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
deps = [
"//foundation/distributeddatamgr/appdatamgr/interfaces/innerkits/native_rdb:native_rdb",
"//third_party/googletest:gtest_main",
]
}
###############################################################################
group("unittest") {
testonly = true
deps = [ ":NativeRdbTest" ]
}
###############################################################################

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_TEST_COMMON_H
#define NATIVE_RDB_TEST_COMMON_H
#include <string>
namespace OHOS {
namespace NativeRdb {
static const std::string RDB_TEST_PATH = "/data/test/";
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_TEST_LOG_PRINT_H
#define NATIVE_RDB_TEST_LOG_PRINT_H
#include "hilog/log.h"
namespace OHOS {
namespace NativeRdb {
static const OHOS::HiviewDFX::HiLogLabel RDB_TEST_LABEL = { LOG_CORE, 0xD001650, "NativeRDB_TEST" };
#define LOG_DEBUG(...) ((void)OHOS::HiviewDFX::HiLog::Debug(RDB_TEST_LABEL, __VA_ARGS__))
#define LOG_INFO(...) ((void)OHOS::HiviewDFX::HiLog::Info(RDB_TEST_LABEL, __VA_ARGS__))
#define LOG_WARN(...) ((void)OHOS::HiviewDFX::HiLog::Warn(RDB_TEST_LABEL, __VA_ARGS__))
#define LOG_ERROR(...) ((void)OHOS::HiviewDFX::HiLog::Error(RDB_TEST_LABEL, __VA_ARGS__))
#define LOG_FATAL(...) ((void)OHOS::HiviewDFX::HiLog::Fatal(RDB_TEST_LABEL, __VA_ARGS__))
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,238 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbAttachTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
void QueryCheck1(std::shared_ptr<RdbStore> &store) const;
void QueryCheck2(std::shared_ptr<RdbStore> &store) const;
static const std::string MAIN_DATABASE_NAME;
static const std::string ATTACHED_DATABASE_NAME;
};
const std::string RdbAttachTest::MAIN_DATABASE_NAME = RDB_TEST_PATH + "main.db";
class MainOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
std::string const MainOpenCallback::CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test1(id INTEGER PRIMARY KEY "
"AUTOINCREMENT, name TEXT NOT NULL)";
int MainOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
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 &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
std::string const AttachedOpenCallback::CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test2(id INTEGER PRIMARY KEY "
"AUTOINCREMENT, name TEXT NOT NULL)";
int AttachedOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
int AttachedOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return E_OK;
}
void RdbAttachTest::SetUpTestCase(void)
{
RdbStoreConfig attachedConfig(RdbAttachTest::ATTACHED_DATABASE_NAME);
AttachedOpenCallback attachedHelper;
int errCode = E_OK;
std::shared_ptr<RdbStore> attachedStore = RdbHelper::GetRdbStore(attachedConfig, 1, attachedHelper, errCode);
EXPECT_NE(attachedStore, nullptr);
}
void RdbAttachTest::TearDownTestCase(void)
{
RdbHelper::DeleteRdbStore(MAIN_DATABASE_NAME);
RdbHelper::DeleteRdbStore(ATTACHED_DATABASE_NAME);
}
void RdbAttachTest::SetUp(void)
{
}
void RdbAttachTest::TearDown(void)
{
}
/**
* @tc.name: RdbStore_Attach_001
* @tc.desc: test attach, attach is not supported in wal mode
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbAttachTest, RdbStore_Attach_001, TestSize.Level1)
{
RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
MainOpenCallback helper;
int errCode = E_OK;
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");
EXPECT_EQ(ret, E_NOT_SUPPROTED_ATTACH_IN_WAL_MODE);
ret = store->ExecuteSql("attach '" + ATTACHED_DATABASE_NAME + "' as attached");
EXPECT_EQ(ret, E_NOT_SUPPROTED_ATTACH_IN_WAL_MODE);
}
/**
* @tc.name: RdbStore_Attach_002
* @tc.desc: test RdbStore attach
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbAttachTest, RdbStore_Attach_002, TestSize.Level1)
{
RdbStoreConfig config(RdbAttachTest::MAIN_DATABASE_NAME);
config.SetJournalMode(JournalMode::MODE_TRUNCATE);
MainOpenCallback helper;
int errCode = E_OK;
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'");
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);
QueryCheck1(store);
ret = store->ExecuteSql("DETACH DATABASE 'attached'");
EXPECT_EQ(ret, E_OK);
QueryCheck2(store);
ret = store->ExecuteSql("attach database '" + ATTACHED_DATABASE_NAME + "' as 'attached'");
EXPECT_EQ(ret, E_OK);
ret = store->ExecuteSql("detach database 'attached'");
EXPECT_EQ(ret, E_OK);
}
void RdbAttachTest::QueryCheck1(std::shared_ptr<RdbStore> &store) const
{
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test1");
EXPECT_NE(resultSet, nullptr);
int ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
int columnIndex;
int intVal;
ret = resultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(intVal, 1);
std::string strVal;
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(strVal, "zhangsan");
resultSet = store->QuerySql("SELECT * FROM test2");
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(intVal, 1);
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(strVal, "lisi");
}
void RdbAttachTest::QueryCheck2(std::shared_ptr<RdbStore> &store) const
{
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test1");
EXPECT_NE(resultSet, nullptr);
int ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
int columnIndex;
int intVal;
ret = resultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(intVal, 1);
std::string strVal;
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(strVal, "zhangsan");
// detached, no table test2
resultSet = store->QuerySql("SELECT * FROM test2");
EXPECT_NE(resultSet, nullptr);
}

View File

@ -0,0 +1,257 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbDeleteTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
static const std::string DATABASE_NAME;
static std::shared_ptr<RdbStore> store;
static const int E_SQLITE_ERROR; // errno SQLITE_ERROR
};
const std::string RdbDeleteTest::DATABASE_NAME = RDB_TEST_PATH + "delete_test.db";
std::shared_ptr<RdbStore> RdbDeleteTest::store = nullptr;
const int RdbDeleteTest::E_SQLITE_ERROR = -1; // errno SQLITE_ERROR
class DeleteTestOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
std::string const DeleteTestOpenCallback::CREATE_TABLE_TEST = std::string("CREATE TABLE IF NOT EXISTS test ")
+ std::string("(id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name TEXT NOT NULL, age INTEGER, salary "
"REAL, blobType BLOB)");
int DeleteTestOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
int DeleteTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return E_OK;
}
void RdbDeleteTest::SetUpTestCase(void)
{
int errCode = E_OK;
RdbStoreConfig config(RdbDeleteTest::DATABASE_NAME);
DeleteTestOpenCallback helper;
RdbDeleteTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(RdbDeleteTest::store, nullptr);
}
void RdbDeleteTest::TearDownTestCase(void)
{
RdbHelper::DeleteRdbStore(RdbDeleteTest::DATABASE_NAME);
}
void RdbDeleteTest::SetUp(void)
{
store->ExecuteSql("DELETE FROM test");
}
void RdbDeleteTest::TearDown(void)
{
}
/**
* @tc.name: RdbStore_Delete_001
* @tc.desc: test RdbStore update, select id and update one row
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbDeleteTest, RdbStore_Delete_001, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDeleteTest::store;
int64_t id;
ValuesBucket values;
int deletedRows;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
ret = store->Delete(deletedRows, "test", "id = 1");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, deletedRows);
std::unique_ptr<ResultSet> resultSet =
store->QuerySql("SELECT * FROM test WHERE id = ?", std::vector<std::string>{ "1" });
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
resultSet = store->QuerySql("SELECT * FROM test WHERE id = ?", std::vector<std::string>{ "2" });
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToFirstRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
resultSet = store->QuerySql("SELECT * FROM test WHERE id = 3", std::vector<std::string>());
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToFirstRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: RdbStore_Delete_002
* @tc.desc: test RdbStore update, select id and update one row
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbDeleteTest, RdbStore_Delete_002, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDeleteTest::store;
int64_t id;
ValuesBucket values;
int deletedRows;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
ret = store->Delete(deletedRows, "test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, deletedRows);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: RdbStore_Delete_003
* @tc.desc: test RdbStore update, select id and update one row
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbDeleteTest, RdbStore_Delete_003, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDeleteTest::store;
int64_t id;
ValuesBucket values;
int deletedRows;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
ret = store->Delete(deletedRows, "", "id = ?", std::vector<std::string>{ "1" });
EXPECT_EQ(ret, E_EMPTY_TABLE_NAME);
ret = store->Delete(deletedRows, "wrongTable", "id = ?", std::vector<std::string>{ "1" });
EXPECT_EQ(ret, RdbDeleteTest::E_SQLITE_ERROR);
ret = store->Delete(deletedRows, "test", "wrong sql id = ?", std::vector<std::string>{ "1" });
EXPECT_EQ(ret, RdbDeleteTest::E_SQLITE_ERROR);
ret = store->Delete(deletedRows, "test", "id = 1", std::vector<std::string>());
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(deletedRows, 1);
}

View File

@ -0,0 +1,707 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include <thread>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbEncryptTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
static void InsertThread(int n);
static void QueryThread(int n);
void QueryCheckID1(std::shared_ptr<RdbStore> &store);
void QueryCheckID4(std::shared_ptr<RdbStore> &store);
void QueryCheckID5(std::shared_ptr<RdbStore> &store);
static const std::string ENCRYPTED_DATABASE_NAME;
static const std::string UNENCRYPTED_DATABASE_NAME;
static const std::vector<uint8_t> KEY1;
static const std::vector<uint8_t> KEY2;
static const std::vector<uint8_t> KEY11;
static const std::vector<uint8_t> KEY12;
static const std::vector<uint8_t> KEY13;
static const int E_SQLITE_NOTADB; // errno SQLITE_NOTADB
static std::shared_ptr<RdbStore> testStore;
};
const std::string RdbEncryptTest::ENCRYPTED_DATABASE_NAME = RDB_TEST_PATH + "encrypted.db";
const std::string RdbEncryptTest::UNENCRYPTED_DATABASE_NAME = RDB_TEST_PATH + "unencrypted.db";
const std::vector<uint8_t> RdbEncryptTest::KEY1 = { 'E', 'n', 'c', 'r', 'y', 'p', 't', 'T', 'e', 's', 't', '@', '1',
'2', '3' };
const std::vector<uint8_t> RdbEncryptTest::KEY2 = { 'E', 'n', 'c', 'r', 'y', 'p', 't', 'T', 'e', 's', 't', '@', '4',
'5', '6' };
const std::vector<uint8_t> RdbEncryptTest::KEY11 = { 'E', 'n', 'c', 'r', 'y', 'p', 't', 'T', 'e', 's', 't', '#', '1',
'2', '3' };
const std::vector<uint8_t> RdbEncryptTest::KEY12 = { 'E', 'n', 'c', 'r', 'y', 'p', 't', 'T', 'e', 's', 't', '!', '4',
'5', '6' };
const std::vector<uint8_t> RdbEncryptTest::KEY13 = { 'E', 'n', 'c', 'r', 'y', 'p', 't', 'T', 'e', 's', 't', '%', '4',
'5', '6' };
const int RdbEncryptTest::E_SQLITE_NOTADB = -26; // errno SQLITE_NOTADB
std::shared_ptr<RdbStore> RdbEncryptTest::testStore = nullptr;
class EncryptTestOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
std::string const EncryptTestOpenCallback::CREATE_TABLE_TEST = std::string("CREATE TABLE IF NOT EXISTS test ")
+ std::string("(id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name TEXT NOT NULL, age INTEGER, salary "
"REAL, blobType BLOB)");
int EncryptTestOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
int EncryptTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return E_OK;
}
void RdbEncryptTest::SetUpTestCase(void)
{
}
void RdbEncryptTest::TearDownTestCase(void)
{
RdbHelper::DeleteRdbStore(RdbEncryptTest::ENCRYPTED_DATABASE_NAME);
RdbHelper::DeleteRdbStore(RdbEncryptTest::UNENCRYPTED_DATABASE_NAME);
}
void RdbEncryptTest::SetUp(void)
{
}
void RdbEncryptTest::TearDown(void)
{
}
/**
* @tc.name: RdbStore_Encrypt_001
* @tc.desc: test RdbStore Encrypt, create with key
* @tc.type: FUNC
* @tc.require: AR000CU2BP
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_001, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, RdbEncryptTest::KEY1);
EncryptTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
EXPECT_NE(store, nullptr);
EXPECT_EQ(config.GetEncryptKey().empty(), true);
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 3);
}
void RdbEncryptTest::QueryCheckID1(std::shared_ptr<RdbStore> &store)
{
std::unique_ptr<ResultSet> resultSet =
store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector<std::string>{ "zhangsan" });
EXPECT_NE(resultSet, nullptr);
int columnIndex;
int intVal;
std::string strVal;
double dVal;
std::vector<uint8_t> blob;
int ret = resultSet->GoToFirstRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, intVal);
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ("zhangsan", strVal);
ret = resultSet->GetColumnIndexForName("age", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(18, intVal);
ret = resultSet->GetColumnIndexForName("salary", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetDouble(columnIndex, dVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(100.5, dVal);
ret = resultSet->GetColumnIndexForName("blobType", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetBlob(columnIndex, blob);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, static_cast<int>(blob.size()));
EXPECT_EQ(1, blob[0]);
EXPECT_EQ(2, blob[1]);
EXPECT_EQ(3, blob[2]);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: RdbStore_Encrypt_002
* @tc.desc: test RdbStore Encrypt, open with correct key
* @tc.type: FUNC
* @tc.require: AR000CU2BP
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_002, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, RdbEncryptTest::KEY1);
EncryptTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
EXPECT_NE(store, nullptr);
RdbEncryptTest::QueryCheckID1(store);
}
/**
* @tc.name: RdbStore_Encrypt_003
* @tc.desc: test RdbStore Encrypt, incorrect key
* @tc.type: FUNC
* @tc.require: AR000CU2BP
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_003, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, RdbEncryptTest::KEY2);
EncryptTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
EXPECT_EQ(store, nullptr);
EXPECT_EQ(errCode, E_SQLITE_NOTADB);
}
/**
* @tc.name: RdbStore_Encrypt_004
* @tc.desc: test RdbStore Encrypt, null key
* @tc.type: FUNC
* @tc.require: AR000CU2BP
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_004, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbEncryptTest::ENCRYPTED_DATABASE_NAME);
EncryptTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_EQ(store, nullptr);
EXPECT_EQ(errCode, E_SQLITE_NOTADB);
}
void RdbEncryptTest::QueryCheckID4(std::shared_ptr<RdbStore> &store)
{
std::unique_ptr<ResultSet> resultSet =
store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector<std::string>{ "zhao" });
EXPECT_NE(resultSet, nullptr);
int columnIndex;
int intVal;
std::string strVal;
double dVal;
std::vector<uint8_t> blob;
int ret = resultSet->GoToFirstRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(4, intVal);
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ("zhao", strVal);
ret = resultSet->GetColumnIndexForName("age", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(40, intVal);
ret = resultSet->GetColumnIndexForName("salary", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetDouble(columnIndex, dVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(400.5, dVal);
ret = resultSet->GetColumnIndexForName("blobType", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetBlob(columnIndex, blob);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, static_cast<int>(blob.size()));
EXPECT_EQ(10, blob[0]);
EXPECT_EQ(11, blob[1]);
EXPECT_EQ(12, blob[2]);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: RdbStore_Encrypt_005
* @tc.desc: test RdbStore Encrypt, change key
* @tc.type: FUNC
* @tc.require: AR000CU2BP
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_005, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, RdbEncryptTest::KEY1);
EncryptTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
EXPECT_NE(store, nullptr);
int ret = store->ChangeEncryptKey(RdbEncryptTest::KEY2);
EXPECT_EQ(ret, E_OK);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 3);
int64_t id;
ValuesBucket values;
values.Clear();
values.PutInt("id", 4);
values.PutString("name", std::string("zhao"));
values.PutInt("age", 40);
values.PutDouble("salary", 400.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 10, 11, 12 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(4, id);
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 4);
RdbEncryptTest::QueryCheckID1(store);
RdbEncryptTest::QueryCheckID4(store);
}
/**
* @tc.name: RdbStore_Encrypt_006
* @tc.desc: test RdbStore Encrypt, open with old key
* @tc.type: FUNC
* @tc.require: AR000CU2BP
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_006, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, RdbEncryptTest::KEY1);
EncryptTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
EXPECT_EQ(store, nullptr);
EXPECT_EQ(errCode, E_SQLITE_NOTADB);
}
/**
* @tc.name: RdbStore_Encrypt_007
* @tc.desc: test RdbStore Encrypt, open with null key
* @tc.type: FUNC
* @tc.require: AR000CU2BP
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_007, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(
RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, std::vector<uint8_t>());
EncryptTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
EXPECT_EQ(store, nullptr);
EXPECT_EQ(errCode, E_SQLITE_NOTADB);
}
/**
* @tc.name: RdbStore_Encrypt_008
* @tc.desc: test RdbStore Encrypt, open with new key
* @tc.type: FUNC
* @tc.require: AR000CU2BP
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_008, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, RdbEncryptTest::KEY2);
EncryptTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
EXPECT_NE(store, nullptr);
int64_t count;
int ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 4);
}
void RdbEncryptTest::QueryCheckID5(std::shared_ptr<RdbStore> &store)
{
std::unique_ptr<ResultSet> resultSet =
store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector<std::string>{ "sun" });
EXPECT_NE(resultSet, nullptr);
int columnIndex;
int intVal;
std::string strVal;
double dVal;
std::vector<uint8_t> blob;
int ret = resultSet->GoToFirstRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(5, intVal);
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ("sun", strVal);
ret = resultSet->GetColumnIndexForName("age", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(50, intVal);
ret = resultSet->GetColumnIndexForName("salary", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetDouble(columnIndex, dVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(500.5, dVal);
ret = resultSet->GetColumnIndexForName("blobType", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetBlob(columnIndex, blob);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, static_cast<int>(blob.size()));
EXPECT_EQ(13, blob[0]);
EXPECT_EQ(14, blob[1]);
EXPECT_EQ(15, blob[2]);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: RdbStore_Encrypt_009
* @tc.desc: test RdbStore Encrypt, change key but new key is null
* @tc.type: FUNC
* @tc.require: AR000CU2BP
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_009, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, RdbEncryptTest::KEY2);
EncryptTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
EXPECT_NE(store, nullptr);
int ret = store->ChangeEncryptKey(std::vector<uint8_t>());
EXPECT_EQ(ret, E_EMPTY_NEW_ENCRYPT_KEY);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 4);
int64_t id;
ValuesBucket values;
values.Clear();
values.PutInt("id", 5);
values.PutString("name", std::string("sun"));
values.PutInt("age", 50);
values.PutDouble("salary", 500.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 13, 14, 15 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(5, id);
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 5);
RdbEncryptTest::QueryCheckID1(store);
RdbEncryptTest::QueryCheckID4(store);
RdbEncryptTest::QueryCheckID5(store);
}
/**
* @tc.name: RdbStore_Encrypt_010
* @tc.desc: test RdbStore Encrypt, change key but the database is unencrypted
* @tc.type: FUNC
* @tc.require: AR000CU2BP
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_010, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbEncryptTest::UNENCRYPTED_DATABASE_NAME);
EncryptTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
int ret = store->ChangeEncryptKey(RdbEncryptTest::KEY2);
EXPECT_EQ(ret, E_CHANGE_UNENCRYPTED_TO_ENCRYPTED);
}
void RdbEncryptTest::InsertThread(int n)
{
std::shared_ptr<RdbStore> &store = RdbEncryptTest::testStore;
int ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
ret = store->MarkAsCommit();
EXPECT_EQ(ret, E_OK);
ret = store->EndTransaction();
EXPECT_EQ(ret, E_OK);
}
void RdbEncryptTest::QueryThread(int n)
{
std::shared_ptr<RdbStore> &store = RdbEncryptTest::testStore;
std::unique_ptr<ResultSet> resultSet =
store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector<std::string>{ "zhangsan" });
EXPECT_NE(resultSet, nullptr);
int ret = resultSet->GoToFirstRow();
EXPECT_EQ(ret, E_OK);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: RdbStore_Encrypt_011
* @tc.desc: test RdbStore Encrypt, change key but the database is busy
* @tc.type: FUNC
* @tc.require: SR000CU2BL
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_011, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, RdbEncryptTest::KEY2);
EncryptTestOpenCallback helper;
RdbEncryptTest::testStore = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
std::shared_ptr<RdbStore> &store = RdbEncryptTest::testStore;
EXPECT_NE(store, nullptr);
std::thread insertThread = std::thread(RdbEncryptTest::InsertThread, 0);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
int ret = store->ChangeEncryptKey(RdbEncryptTest::KEY11);
EXPECT_EQ(ret, E_CHANGE_ENCRYPT_KEY_IN_BUSY);
insertThread.join();
ret = store->ChangeEncryptKey(RdbEncryptTest::KEY11);
EXPECT_EQ(ret, E_OK);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 5);
int64_t id;
ValuesBucket values;
values.Clear();
values.PutInt("id", 6);
values.PutString("name", std::string("he"));
values.PutInt("age", 60);
values.PutDouble("salary", 600.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 16, 17, 18 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(6, id);
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 6);
RdbEncryptTest::QueryCheckID1(store);
}
/**
* @tc.name: RdbStore_Encrypt_012
* @tc.desc: test RdbStore Encrypt, change key but the database is busy
* @tc.type: FUNC
* @tc.require: SR000CU2BL
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_012, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(
RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, RdbEncryptTest::KEY11);
EncryptTestOpenCallback helper;
RdbEncryptTest::testStore = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
std::shared_ptr<RdbStore> &store = RdbEncryptTest::testStore;
EXPECT_NE(store, nullptr);
std::thread queryThread = std::thread(RdbEncryptTest::QueryThread, 0);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
int ret = store->ChangeEncryptKey(RdbEncryptTest::KEY12);
EXPECT_EQ(ret, E_CHANGE_ENCRYPT_KEY_IN_BUSY);
queryThread.join();
ret = store->ChangeEncryptKey(RdbEncryptTest::KEY12);
EXPECT_EQ(ret, E_OK);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 6);
int64_t id;
ValuesBucket values;
values.Clear();
values.PutInt("id", 7);
values.PutString("name", std::string("he"));
values.PutInt("age", 30);
values.PutDouble("salary", 700.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 16, 17, 18 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(7, id);
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 7);
RdbEncryptTest::QueryCheckID1(store);
}
/**
* @tc.name: RdbStore_Encrypt_013
* @tc.desc: test RdbStore Encrypt, change key but the database is busy
* @tc.type: FUNC
* @tc.require: SR000CU2BL
* @tc.author: chenxi
*/
HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_013, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(
RdbEncryptTest::ENCRYPTED_DATABASE_NAME, StorageMode::MODE_DISK, false, RdbEncryptTest::KEY12);
EncryptTestOpenCallback helper;
RdbEncryptTest::testStore = RdbHelper::GetRdbStore(config, 1, helper, errCode);
config.ClearEncryptKey();
std::shared_ptr<RdbStore> &store = RdbEncryptTest::testStore;
EXPECT_NE(store, nullptr);
std::thread insertThread = std::thread(RdbEncryptTest::InsertThread, 0);
std::thread queryThread = std::thread(RdbEncryptTest::QueryThread, 0);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
int ret = store->ChangeEncryptKey(RdbEncryptTest::KEY13);
EXPECT_EQ(ret, E_CHANGE_ENCRYPT_KEY_IN_BUSY);
insertThread.join();
queryThread.join();
ret = store->ChangeEncryptKey(RdbEncryptTest::KEY13);
EXPECT_EQ(ret, E_OK);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 7);
int64_t id;
ValuesBucket values;
values.Clear();
values.PutInt("id", 8);
values.PutString("name", std::string("wu"));
values.PutInt("age", 40);
values.PutDouble("salary", 800.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 16, 17, 18 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(8, id);
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 8);
RdbEncryptTest::QueryCheckID1(store);
}

View File

@ -0,0 +1,244 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbExecuteTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
static const std::string DATABASE_NAME;
static std::shared_ptr<RdbStore> store;
static const int E_SQLITE_ERROR; // errno SQLITE_ERROR
};
const std::string RdbExecuteTest::DATABASE_NAME = RDB_TEST_PATH + "execute_test.db";
std::shared_ptr<RdbStore> RdbExecuteTest::store = nullptr;
const int RdbExecuteTest::E_SQLITE_ERROR = -1; // errno SQLITE_ERROR
class ExecuteTestOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
const std::string ExecuteTestOpenCallback::CREATE_TABLE_TEST = std::string("CREATE TABLE IF NOT EXISTS test ")
+ std::string("(id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name TEXT NOT NULL, age INTEGER, salary "
"REAL, blobType BLOB)");
int ExecuteTestOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
int ExecuteTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return E_OK;
}
void RdbExecuteTest::SetUpTestCase(void)
{
int errCode = E_OK;
RdbStoreConfig config(RdbExecuteTest::DATABASE_NAME);
ExecuteTestOpenCallback helper;
RdbExecuteTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(RdbExecuteTest::store, nullptr);
EXPECT_EQ(errCode, E_OK);
}
void RdbExecuteTest::TearDownTestCase(void)
{
RdbHelper::DeleteRdbStore(RdbExecuteTest::DATABASE_NAME);
}
void RdbExecuteTest::SetUp(void)
{
store->ExecuteSql("DELETE FROM test");
}
void RdbExecuteTest::TearDown(void)
{
}
/**
* @tc.name: RdbStore_Execute_001
* @tc.desc: test RdbStore Execute
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbExecuteTest, RdbStore_Execute_001, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbExecuteTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 3);
ret = store->ExecuteSql("DELETE FROM test WHERE age = ? OR age = ?",
std::vector<ValueObject>{ ValueObject(std::string("18")), ValueObject(std ::string("20")) });
EXPECT_EQ(ret, E_OK);
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test where age = 19");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 1);
ret = store->ExecuteSql("DELETE FROM test WHERE age = 19");
EXPECT_EQ(ret, E_OK);
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 0);
}
/**
* @tc.name: RdbStore_Execute_002
* @tc.desc: test RdbStore Execute
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbExecuteTest, RdbStore_Execute_002, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbExecuteTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(3, id);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test", std::vector<ValueObject>());
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 3);
ret = store->ExecuteSql("DELETE FROM test WHERE age = ? OR age = ?",
std::vector<ValueObject>{ ValueObject(std::string("18")), ValueObject(std ::string("20")) });
EXPECT_EQ(ret, E_OK);
ret = store->ExecuteAndGetLong(
count, "SELECT COUNT(*) FROM test where age = ?", std::vector<ValueObject>{ ValueObject(std::string("19")) });
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 1);
ret = store->ExecuteSql("DELETE FROM test WHERE age = 19");
EXPECT_EQ(ret, E_OK);
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test", std::vector<ValueObject>());
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 0);
ret = store->ExecuteSql("DROP TABLE IF EXISTS test");
EXPECT_EQ(ret, E_OK);
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, -1);
}
/**
* @tc.name: RdbStore_Execute_003
* @tc.desc: test RdbStore Execute
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbExecuteTest, RdbStore_Execute_003, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbExecuteTest::store;
int64_t pageSize;
int ret = store->ExecuteAndGetLong(pageSize, "PRAGMA page_size");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(pageSize, 4096);
std::string journalMode;
ret = store->ExecuteAndGetString(journalMode, "PRAGMA journal_mode");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(journalMode, "wal");
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2021 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 "rdb_helper.h"
#include <gtest/gtest.h>
#include <string>
#include "rdb_errno.h"
#include "rdb_open_callback.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbHelperTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
};
void RdbHelperTest::SetUpTestCase(void)
{
}
void RdbHelperTest::TearDownTestCase(void)
{
}
void RdbHelperTest::SetUp(void)
{
}
void RdbHelperTest::TearDown(void)
{
}
/**
* @tc.name: DeleteDatabase_001
* @tc.desc: delete db file
* @tc.type: FUNC
* @tc.require: SR000CU2BL
* @tc.author: chenxi
*/
HWTEST_F(RdbHelperTest, DeleteDatabase_001, TestSize.Level1)
{
int ret = RdbHelper::DeleteRdbStore("test");
EXPECT_EQ(ret, E_OK);
}

View File

@ -0,0 +1,691 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbStoreInsertTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
void CheckResultSet(std::shared_ptr<RdbStore> &store);
void CheckAge(std::unique_ptr<ResultSet> &resultSet);
void CheckSalary(std::unique_ptr<ResultSet> &resultSet);
void CheckBlob(std::unique_ptr<ResultSet> &resultSet);
static const std::string DATABASE_NAME;
static std::shared_ptr<RdbStore> store;
static const int E_SQLITE_ERROR; // errno SQLITE_ERROR
static const int E_SQLITE_CONSTRAINT; // errno SQLITE_CONSTRAINT
};
const std::string RdbStoreInsertTest::DATABASE_NAME = RDB_TEST_PATH + "insert_test.db";
std::shared_ptr<RdbStore> RdbStoreInsertTest::store = nullptr;
const int RdbStoreInsertTest::E_SQLITE_CONSTRAINT = -19;
const int RdbStoreInsertTest::E_SQLITE_ERROR = -1;
class InsertTestOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
const std::string InsertTestOpenCallback::CREATE_TABLE_TEST = std::string("CREATE TABLE IF NOT EXISTS test ")
+ std::string("(id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name TEXT NOT NULL, age INTEGER, salary "
"REAL, blobType BLOB)");
int InsertTestOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
int InsertTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return E_OK;
}
void RdbStoreInsertTest::SetUpTestCase(void)
{
int errCode = E_OK;
RdbStoreConfig config(RdbStoreInsertTest::DATABASE_NAME);
InsertTestOpenCallback helper;
RdbStoreInsertTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(RdbStoreInsertTest::store, nullptr);
}
void RdbStoreInsertTest::TearDownTestCase(void)
{
RdbHelper::DeleteRdbStore(RdbStoreInsertTest::DATABASE_NAME);
}
void RdbStoreInsertTest::SetUp(void)
{
store->ExecuteSql("DELETE FROM test");
}
void RdbStoreInsertTest::TearDown(void)
{
}
/**
* @tc.name: RdbStore_Insert_001
* @tc.desc: test RdbStore insert
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_Insert_001, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 20L);
values.PutDouble("salary", 100.5f);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
RdbStoreInsertTest::CheckResultSet(store);
}
void RdbStoreInsertTest::CheckResultSet(std::shared_ptr<RdbStore> &store)
{
std::unique_ptr<ResultSet> resultSet =
store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector<std::string>{ "zhangsan" });
EXPECT_NE(resultSet, nullptr);
int columnIndex;
int intVal;
std::string strVal;
ColumnType columnType;
int position;
int ret = resultSet->GetRowIndex(position);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(position, -1);
ret = resultSet->GetColumnTypeForIndex(0, columnType);
EXPECT_EQ(ret, E_STEP_RESULT_QUERY_NOT_EXECUTED);
ret = resultSet->GoToFirstRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(columnIndex, 0);
ret = resultSet->GetColumnTypeForIndex(columnIndex, columnType);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(columnType, ColumnType::TYPE_INTEGER);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, intVal);
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetColumnTypeForIndex(columnIndex, columnType);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(columnType, ColumnType::TYPE_STRING);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ("zhangsan", strVal);
RdbStoreInsertTest::CheckAge(resultSet);
RdbStoreInsertTest::CheckSalary(resultSet);
RdbStoreInsertTest::CheckBlob(resultSet);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->GetColumnTypeForIndex(columnIndex, columnType);
EXPECT_EQ(ret, E_STEP_RESULT_QUERY_NOT_EXECUTED);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
}
void RdbStoreInsertTest::CheckAge(std::unique_ptr<ResultSet> &resultSet)
{
int columnIndex;
int intVal;
ColumnType columnType;
int ret = resultSet->GetColumnIndexForName("age", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetColumnTypeForIndex(columnIndex, columnType);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(columnType, ColumnType::TYPE_INTEGER);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(18, intVal);
}
void RdbStoreInsertTest::CheckSalary(std::unique_ptr<ResultSet> &resultSet)
{
int columnIndex;
double dVal;
ColumnType columnType;
int ret = resultSet->GetColumnIndexForName("salary", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetColumnTypeForIndex(columnIndex, columnType);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(columnType, ColumnType::TYPE_FLOAT);
ret = resultSet->GetDouble(columnIndex, dVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(100.5, dVal);
}
void RdbStoreInsertTest::CheckBlob(std::unique_ptr<ResultSet> &resultSet)
{
int columnIndex;
std::vector<uint8_t> blob;
ColumnType columnType;
int ret = resultSet->GetColumnIndexForName("blobType", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetColumnTypeForIndex(columnIndex, columnType);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(columnType, ColumnType::TYPE_BLOB);
ret = resultSet->GetBlob(columnIndex, blob);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, static_cast<int>(blob.size()));
EXPECT_EQ(1, blob[0]);
EXPECT_EQ(2, blob[1]);
EXPECT_EQ(3, blob[2]);
}
/**
* @tc.name: RdbStore_Insert_002
* @tc.desc: test RdbStore insert
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_Insert_002, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "", values); // empty table name
EXPECT_EQ(ret, E_EMPTY_TABLE_NAME);
ret = store->Insert(id, "wrongTable", values); // no such table
EXPECT_EQ(ret, RdbStoreInsertTest::E_SQLITE_ERROR);
}
/**
* @tc.name: RdbStore_Insert_003
* @tc.desc: test RdbStore insert
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_Insert_003, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket emptyBucket;
int ret = store->Insert(id, "test", emptyBucket);
EXPECT_EQ(ret, E_EMPTY_VALUES_BUCKET);
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("wrongColumn", 100.5); // no such column
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, RdbStoreInsertTest::E_SQLITE_ERROR);
}
/**
* @tc.name: RdbStore_Replace_001
* @tc.desc: test RdbStore replace
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_Replace_001, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Replace(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
int columnIndex;
int intVal;
std::string strVal;
double dVal;
std::vector<uint8_t> blob;
ret = resultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, intVal);
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ("zhangsan", strVal);
ret = resultSet->GetColumnIndexForName("age", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(18, intVal);
ret = resultSet->GetColumnIndexForName("salary", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetDouble(columnIndex, dVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(100.5, dVal);
ret = resultSet->GetColumnIndexForName("blobType", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetBlob(columnIndex, blob);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, static_cast<int>(blob.size()));
EXPECT_EQ(1, blob[0]);
EXPECT_EQ(2, blob[1]);
EXPECT_EQ(3, blob[2]);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: RdbStore_Replace_002
* @tc.desc: test RdbStore replace
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_Replace_002, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Replace(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
int columnIndex;
int intVal;
std::string strVal;
double dVal;
std::vector<uint8_t> blob;
ret = resultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, intVal);
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ("zhangsan", strVal);
ret = resultSet->GetColumnIndexForName("age", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(18, intVal);
ret = resultSet->GetColumnIndexForName("salary", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetDouble(columnIndex, dVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(200.5, dVal);
ret = resultSet->GetColumnIndexForName("blobType", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetBlob(columnIndex, blob);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, static_cast<int>(blob.size()));
EXPECT_EQ(1, blob[0]);
EXPECT_EQ(2, blob[1]);
EXPECT_EQ(3, blob[2]);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: RdbStore_Replace_003
* @tc.desc: test RdbStore Replace
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_Replace_003, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Replace(id, "", values); // empty table name
EXPECT_EQ(ret, E_EMPTY_TABLE_NAME);
ret = store->Replace(id, "wrongTable", values); // no such table
EXPECT_EQ(ret, RdbStoreInsertTest::E_SQLITE_ERROR);
}
/**
* @tc.name: RdbStore_Replace_004
* @tc.desc: test RdbStore Replace
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_Replace_004, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket emptyBucket;
int ret = store->Replace(id, "test", emptyBucket);
EXPECT_EQ(ret, E_EMPTY_VALUES_BUCKET);
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("wrongColumn", 100.5); // no such column
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Replace(id, "test", values);
EXPECT_EQ(ret, RdbStoreInsertTest::E_SQLITE_ERROR);
}
/**
* @tc.name: RdbStore_InsertWithConflictResolution_001_002
* @tc.desc: test RdbStore InsertWithConflictResolution
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_InsertWithConflictResolution_001_002, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
// default is ConflictResolution::ON_CONFLICT_NONE
int ret = store->InsertWithConflictResolution(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->InsertWithConflictResolution(id, "test", values);
EXPECT_EQ(ret, RdbStoreInsertTest::E_SQLITE_CONSTRAINT);
}
/**
* @tc.name: RdbStore_InsertWithConflictResolution_003_004
* @tc.desc: test RdbStore InsertWithConflictResolution
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_InsertWithConflictResolution_003_004, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->InsertWithConflictResolution(id, "test", values, ConflictResolution::ON_CONFLICT_ROLLBACK);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->InsertWithConflictResolution(id, "test", values, ConflictResolution::ON_CONFLICT_ROLLBACK);
EXPECT_EQ(ret, RdbStoreInsertTest::E_SQLITE_CONSTRAINT);
}
/**
* @tc.name: RdbStore_InsertWithConflictResolution_005
* @tc.desc: test RdbStore InsertWithConflictResolution
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_InsertWithConflictResolution_005, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->InsertWithConflictResolution(id, "test", values, ConflictResolution::ON_CONFLICT_IGNORE);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->InsertWithConflictResolution(id, "test", values, ConflictResolution::ON_CONFLICT_IGNORE);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(id, -1);
}
/**
* @tc.name: RdbStore_InsertWithConflictResolution_006_007
* @tc.desc: test RdbStore InsertWithConflictResolution
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInsertTest, RdbStore_InsertWithConflictResolution_006_007, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbStoreInsertTest::store;
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->InsertWithConflictResolution(id, "test", values, ConflictResolution::ON_CONFLICT_REPLACE);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->InsertWithConflictResolution(id, "test", values, ConflictResolution::ON_CONFLICT_REPLACE);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(id, 1);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
int columnIndex;
int intVal;
std::string strVal;
double dVal;
std::vector<uint8_t> blob;
ret = resultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, intVal);
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ("zhangsan", strVal);
ret = resultSet->GetColumnIndexForName("age", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetInt(columnIndex, intVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(18, intVal);
ret = resultSet->GetColumnIndexForName("salary", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetDouble(columnIndex, dVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(200.5, dVal);
ret = resultSet->GetColumnIndexForName("blobType", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetBlob(columnIndex, blob);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, static_cast<int>(blob.size()));
EXPECT_EQ(4, blob[0]);
EXPECT_EQ(5, blob[1]);
EXPECT_EQ(6, blob[2]);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
}

View File

@ -0,0 +1,391 @@
/*
* Copyright (c) 2021 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 "rdb_open_callback.h"
#include <gtest/gtest.h>
#include <string>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbOpenCallbackTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
static const std::string DATABASE_NAME;
};
const std::string RdbOpenCallbackTest::DATABASE_NAME = RDB_TEST_PATH + "open_helper.db";
void RdbOpenCallbackTest::SetUpTestCase(void)
{
}
void RdbOpenCallbackTest::TearDownTestCase(void)
{
RdbHelper::DeleteRdbStore(RdbOpenCallbackTest::DATABASE_NAME);
}
void RdbOpenCallbackTest::SetUp(void)
{
}
void RdbOpenCallbackTest::TearDown(void)
{
}
class OpenCallbackA : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
int OnDowngrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
int OnOpen(RdbStore &rdbStore) override;
static std::string CreateTableSQL(const std::string &tableName);
static std::string DropTableSQL(const std::string &tableName);
};
std::string OpenCallbackA::CreateTableSQL(const std::string &tableName)
{
return "CREATE TABLE IF NOT EXISTS " + tableName
+ " (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER)";
}
std::string OpenCallbackA::DropTableSQL(const std::string &tableName)
{
return "DROP TABLE IF EXISTS " + tableName + ";";
}
int OpenCallbackA::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CreateTableSQL("test1"));
}
int OpenCallbackA::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
LOG_INFO("RdbOpenCallbackTest onUpgrade begin.");
if (oldVersion < newVersion) {
if (oldVersion <= 1) {
return store.ExecuteSql(CreateTableSQL("test2"));
}
}
return E_OK;
}
int OpenCallbackA::OnDowngrade(RdbStore &store, int oldVersion, int newVersion)
{
LOG_INFO("RdbOpenCallbackTest OnDowngrade begin");
if (oldVersion > newVersion) {
if (oldVersion >= 2) {
return store.ExecuteSql(DropTableSQL("test2"));
}
}
return E_OK;
}
int OpenCallbackA::OnOpen(RdbStore &store)
{
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
int errCode = store.Replace(id, "test1", values);
if (errCode != E_OK) {
return errCode;
}
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 18);
errCode = store.Replace(id, "test1", values);
if (errCode != E_OK) {
return errCode;
}
return E_OK;
}
/**
* @tc.name: RdbOpenCallback_01
* @tc.desc: test RdbOpenCallback
* @tc.type: FUNC
* @tc.require: SR000CU2BL
* @tc.author: chenxi
*/
HWTEST_F(RdbOpenCallbackTest, RdbOpenCallback_01, TestSize.Level1)
{
RdbStoreConfig config(RdbOpenCallbackTest::DATABASE_NAME);
OpenCallbackA helper;
int errCode = E_OK;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
EXPECT_EQ(errCode, E_OK);
int currentVersion;
int ret = store->GetVersion(currentVersion);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentVersion, 1);
int64_t id;
int changedRows;
ValuesBucket values;
values.PutInt("id", 3);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 20);
ret = store->Replace(id, "test1", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
values.Clear();
values.PutInt("age", 20);
ret = store->Update(changedRows, "test1", values, "age = ?", std::vector<std::string>{ "18" });
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, changedRows);
ret = store->Delete(changedRows, "test1", "age = ?", std::vector<std::string>{ "20" });
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, changedRows);
}
/**
* @tc.name: RdbOpenCallback_02
* @tc.desc: test RdbOpenCallback
* @tc.type: FUNC
* @tc.require: SR000CU2BL
* @tc.author: chenxi
*/
HWTEST_F(RdbOpenCallbackTest, RdbOpenCallback_02, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbOpenCallbackTest::DATABASE_NAME);
OpenCallbackA helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 2, helper, errCode);
EXPECT_NE(store, nullptr);
int currentVersion;
int ret = store->GetVersion(currentVersion);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentVersion, 2);
int64_t id;
int changedRows;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
ret = store->Insert(id, "test2", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 18);
ret = store->Insert(id, "test2", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3L);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 20);
ret = store->Insert(id, "test2", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
values.Clear();
values.PutInt("age", 20);
ret = store->Update(changedRows, "test2", values, "age = ?", std::vector<std::string>{ "18" });
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, changedRows);
ret = store->Delete(changedRows, "test2", "age = ?", std::vector<std::string>{ "20" });
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, changedRows);
}
/**
* @tc.name: RdbOpenCallback_03
* @tc.desc: test RdbOpenCallback
* @tc.type: FUNC
* @tc.require: SR000CU2BL
* @tc.author: chenxi
*/
HWTEST_F(RdbOpenCallbackTest, RdbOpenCallback_03, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbOpenCallbackTest::DATABASE_NAME);
OpenCallbackA helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
int currentVersion;
int ret = store->GetVersion(currentVersion);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentVersion, 1);
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
ret = store->Insert(id, "test2", values);
EXPECT_NE(ret, E_OK);
}
class OpenCallbackB : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static std::string CreateTableSQL(const std::string &tableName);
static std::string DropTableSQL(const std::string &tableName);
};
std::string OpenCallbackB::CreateTableSQL(const std::string &tableName)
{
return "CREATE TABLE IF NOT EXISTS " + tableName
+ " (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER)";
}
std::string OpenCallbackB::DropTableSQL(const std::string &tableName)
{
return "DROP TABLE IF EXISTS " + tableName + ";";
}
int OpenCallbackB::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CreateTableSQL("test1"));
}
int OpenCallbackB::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
if (oldVersion < newVersion) {
if (oldVersion <= 1) {
return store.ExecuteSql(CreateTableSQL("test2"));
}
}
return E_OK;
}
/**
* @tc.name: RdbOpenCallback_04
* @tc.desc: test RdbOpenCallback
* @tc.type: FUNC
* @tc.require: SR000CU2BL AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbOpenCallbackTest, RdbOpenCallback_04, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbOpenCallbackTest::DATABASE_NAME);
OpenCallbackB helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 2, helper, errCode);
EXPECT_NE(store, nullptr);
int currentVersion;
int ret = store->GetVersion(currentVersion);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentVersion, 2);
int64_t id;
int changedRows;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
ret = store->Insert(id, "test2", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 18);
ret = store->Insert(id, "test2", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3L);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 20);
ret = store->Insert(id, "test2", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
values.Clear();
values.PutInt("age", 20);
ret = store->Update(changedRows, "test2", values, "age = ?", std::vector<std::string>{ "18" });
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, changedRows);
ret = store->Delete(changedRows, "test2", "age = ?", std::vector<std::string>{ "20" });
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, changedRows);
}
/**
* @tc.name: RdbOpenCallback_05
* @tc.desc: test RdbOpenCallback
* @tc.type: FUNC
* @tc.require: SR000CU2BL AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbOpenCallbackTest, RdbOpenCallback_05, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbOpenCallbackTest::DATABASE_NAME);
OpenCallbackB helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
int currentVersion;
int ret = store->GetVersion(currentVersion);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentVersion, 1);
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
ret = store->Insert(id, "test2", values);
EXPECT_EQ(ret, E_OK);
ret = helper.OnDowngrade(*store, 2, 1);
EXPECT_EQ(ret, E_OK);
ret = helper.OnOpen(*store);
EXPECT_EQ(ret, E_OK);
}

View File

@ -0,0 +1,318 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include <thread>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbConcurrentTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
static const std::string DATABASE_NAME;
static std::shared_ptr<RdbStore> store;
static void InsertThread(int n);
static void QueryThread(int n);
static int Query();
static int CheckResultSet(ResultSet &resultSet);
static int CheckId(ResultSet &resultSet);
static int CheckName(ResultSet &resultSet);
static int CheckAge(ResultSet &resultSet);
static int CheckSalary(ResultSet &resultSet);
static int CheckBlob(ResultSet &resultSet);
static int insertResult;
static int queryResult;
};
const std::string RdbConcurrentTest::DATABASE_NAME = RDB_TEST_PATH + "concurrent_test.db";
std::shared_ptr<RdbStore> RdbConcurrentTest::store = nullptr;
int RdbConcurrentTest::insertResult = E_OK;
int RdbConcurrentTest::queryResult = E_OK;
class ConcurrentTestOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
const std::string ConcurrentTestOpenCallback::CREATE_TABLE_TEST = std::string("CREATE TABLE IF NOT EXISTS test ")
+ std::string("(id INTEGER PRIMARY KEY "
"AUTOINCREMENT, name TEXT NOT NULL, "
"age INTEGER, salary REAL, blobType "
"BLOB)");
int ConcurrentTestOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
int ConcurrentTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return E_OK;
}
void RdbConcurrentTest::SetUpTestCase(void)
{
int errCode = E_OK;
RdbStoreConfig config(RdbConcurrentTest::DATABASE_NAME);
ConcurrentTestOpenCallback helper;
RdbConcurrentTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(RdbConcurrentTest::store, nullptr);
EXPECT_EQ(errCode, E_OK);
}
void RdbConcurrentTest::TearDownTestCase(void)
{
RdbHelper::DeleteRdbStore(RdbConcurrentTest::DATABASE_NAME);
}
void RdbConcurrentTest::SetUp(void)
{
store->ExecuteSql("DELETE FROM test");
}
void RdbConcurrentTest::TearDown(void)
{
}
void RdbConcurrentTest::InsertThread(int n)
{
insertResult = E_OK;
std::shared_ptr<RdbStore> &store = RdbConcurrentTest::store;
ValuesBucket values;
int64_t id;
int i;
for (i = 1; i <= n; i++) {
values.Clear();
values.PutInt("id", i);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
if (ret != E_OK) {
insertResult = ret;
break;
}
if (id != i) {
insertResult = E_ERROR;
break;
}
}
}
void RdbConcurrentTest::QueryThread(int n)
{
queryResult = E_OK;
for (int i = 1; i <= n; i++) {
int errCode = Query();
if (errCode != E_OK) {
queryResult = errCode;
return;
}
}
}
int RdbConcurrentTest::Query()
{
std::shared_ptr<RdbStore> &store = RdbConcurrentTest::store;
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
if (resultSet == nullptr) {
return E_ERROR;
}
while (1) {
int ret = resultSet->GoToNextRow();
if (ret == E_OK) {
int errCode = CheckResultSet(*resultSet);
if (errCode != E_OK) {
return errCode;
}
} else if (ret == E_STEP_RESULT_IS_AFTER_LASET) {
break;
} else {
return ret;
}
}
resultSet->Close();
return E_OK;
}
int RdbConcurrentTest::CheckResultSet(ResultSet &resultSet)
{
int errCode = CheckId(resultSet);
if (errCode != E_OK) {
return errCode;
}
errCode = CheckName(resultSet);
if (errCode != E_OK) {
return errCode;
}
errCode = CheckAge(resultSet);
if (errCode != E_OK) {
return errCode;
}
errCode = CheckSalary(resultSet);
if (errCode != E_OK) {
return errCode;
}
errCode = CheckBlob(resultSet);
if (errCode != E_OK) {
return errCode;
}
return errCode;
}
int RdbConcurrentTest::CheckId(ResultSet &resultSet)
{
int columnIndex;
int intVal;
int errCode = resultSet.GetColumnIndexForName("id", columnIndex);
if (errCode != E_OK) {
return errCode;
}
errCode = resultSet.GetInt(columnIndex, intVal);
if (errCode != E_OK) {
return errCode;
}
return E_OK;
}
int RdbConcurrentTest::CheckName(ResultSet &resultSet)
{
int columnIndex;
std::string strVal;
int errCode = resultSet.GetColumnIndexForName("name", columnIndex);
if (errCode != E_OK) {
return errCode;
}
errCode = resultSet.GetString(columnIndex, strVal);
if (errCode != E_OK) {
return errCode;
}
if (strVal != "zhangsan") {
return E_ERROR;
}
return E_OK;
}
int RdbConcurrentTest::CheckAge(ResultSet &resultSet)
{
int columnIndex;
int intVal;
int errCode = resultSet.GetColumnIndexForName("age", columnIndex);
if (errCode != E_OK) {
return errCode;
}
errCode = resultSet.GetInt(columnIndex, intVal);
if (errCode != E_OK) {
return errCode;
}
if (intVal != 18) {
return E_ERROR;
}
return E_OK;
}
int RdbConcurrentTest::CheckSalary(ResultSet &resultSet)
{
int columnIndex;
double dVal;
int errCode = resultSet.GetColumnIndexForName("salary", columnIndex);
if (errCode != E_OK) {
return errCode;
}
errCode = resultSet.GetDouble(columnIndex, dVal);
if (errCode != E_OK) {
return errCode;
}
if (dVal != 100.5) {
return E_ERROR;
}
return E_OK;
}
int RdbConcurrentTest::CheckBlob(ResultSet &resultSet)
{
int columnIndex;
std::vector<uint8_t> blob;
int errCode = resultSet.GetColumnIndexForName("blobType", columnIndex);
if (errCode != E_OK) {
return errCode;
}
errCode = resultSet.GetBlob(columnIndex, blob);
if (errCode != E_OK) {
return errCode;
}
if (static_cast<int>(blob.size()) != 3) {
return E_ERROR;
}
if (blob[0] != 1 || blob[1] != 2 || blob[3] != 2) {
return E_ERROR;
}
return E_OK;
}
/**
* @tc.name: RdbStore_Concurrent_001
* @tc.desc: test RdbStore Execute
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbConcurrentTest, RdbStore_Concurrent_001, TestSize.Level1)
{
std::thread insertThread = std::thread(RdbConcurrentTest::InsertThread, 5);
std::thread queryThread = std::thread(RdbConcurrentTest::QueryThread, 5);
insertThread.join();
queryThread.join();
EXPECT_EQ(insertResult, E_OK);
}

View File

@ -0,0 +1,371 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
#include "unistd.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbStoreConfigTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
};
class ConfigTestOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
const std::string ConfigTestOpenCallback::CREATE_TABLE_TEST = std::string("CREATE TABLE IF NOT EXISTS test ")
+ std::string("(id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name TEXT NOT NULL, age INTEGER, salary "
"REAL, blobType BLOB)");
int ConfigTestOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
int ConfigTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return E_OK;
}
void RdbStoreConfigTest::SetUpTestCase(void)
{
}
void RdbStoreConfigTest::TearDownTestCase(void)
{
RdbHelper::DeleteRdbStore(RDB_TEST_PATH + "config_test.db");
}
void RdbStoreConfigTest::SetUp(void)
{
}
void RdbStoreConfigTest::TearDown(void)
{
}
/**
* @tc.name: RdbStoreConfig_001
* @tc.desc: test RdbStoreConfig
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_001, TestSize.Level1)
{
int errCode = E_OK;
const std::string dbPath = RDB_TEST_PATH + "config_test.db";
RdbStoreConfig config(dbPath, StorageMode::MODE_DISK, false);
ConfigTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
EXPECT_EQ(errCode, E_OK);
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
ret = access(dbPath.c_str(), F_OK);
EXPECT_EQ(ret, 0);
int currentVersion;
ret = store->GetVersion(currentVersion);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, currentVersion);
store = nullptr;
ret = RdbHelper::DeleteRdbStore(dbPath);
EXPECT_EQ(ret, E_OK);
StorageMode mode = config.GetStorageMode();
StorageMode targeMode = StorageMode::MODE_DISK;
EXPECT_EQ(mode, targeMode);
}
/**
* @tc.name: RdbStoreConfig_002
* @tc.desc: test RdbStoreConfig
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_002, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config("", StorageMode::MODE_MEMORY);
ConfigTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
EXPECT_EQ(errCode, E_OK);
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
int currentVersion;
ret = store->GetVersion(currentVersion);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, currentVersion);
std::string journalMode;
ret = store->ExecuteAndGetString(journalMode, "PRAGMA journal_mode");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(journalMode, "memory");
StorageMode mode = config.GetStorageMode();
StorageMode targeMode = StorageMode::MODE_MEMORY;
EXPECT_EQ(mode, targeMode);
}
/**
* @tc.name: RdbStoreConfig_003
* @tc.desc: test RdbStoreConfig
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_003, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config("", StorageMode::MODE_DISK, false);
ConfigTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_EQ(store, nullptr);
EXPECT_EQ(errCode, E_EMPTY_FILE_NAME);
}
/**
* @tc.name: RdbStoreConfig_004
* @tc.desc: test RdbStoreConfig
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_004, TestSize.Level1)
{
int errCode = E_OK;
const std::string dbPath = "config_test.db";
RdbStoreConfig config(dbPath, StorageMode::MODE_DISK, false);
ConfigTestOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_EQ(store, nullptr);
EXPECT_EQ(errCode, E_RELATIVE_PATH);
}
/**
* @tc.name: RdbStoreConfig_005
* @tc.desc: test RdbStoreConfig journalMode
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_005, TestSize.Level1)
{
const std::string dbPath = RDB_TEST_PATH + "config_test.db";
RdbStoreConfig config(dbPath, StorageMode::MODE_DISK, false);
std::string journalMode = config.GetJournalMode();
EXPECT_EQ(journalMode, "");
ConfigTestOpenCallback helper;
int errCode = E_OK;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
std::string currentMode;
int ret = store->ExecuteAndGetString(currentMode, "PRAGMA journal_mode");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentMode, "wal");
}
/**
* @tc.name: RdbStoreConfig_006
* @tc.desc: test RdbStoreConfig journalMode
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_006, TestSize.Level1)
{
const std::string dbPath = RDB_TEST_PATH + "config_test.db";
RdbStoreConfig config(dbPath, StorageMode::MODE_DISK, false);
config.SetJournalMode(JournalMode::MODE_DELETE);
std::string journalMode = config.GetJournalMode();
EXPECT_EQ(journalMode, "DELETE");
ConfigTestOpenCallback helper;
int errCode = E_OK;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
std::string currentMode;
int ret = store->ExecuteAndGetString(currentMode, "PRAGMA journal_mode");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentMode, "delete");
}
/**
* @tc.name: RdbStoreConfig_007
* @tc.desc: test RdbStoreConfig journalMode
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_007, TestSize.Level1)
{
const std::string dbPath = RDB_TEST_PATH + "config_test.db";
RdbStoreConfig config(dbPath, StorageMode::MODE_DISK, false);
config.SetJournalMode(JournalMode::MODE_TRUNCATE);
std::string journalMode = config.GetJournalMode();
EXPECT_EQ(journalMode, "TRUNCATE");
ConfigTestOpenCallback helper;
int errCode = E_OK;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
std::string currentMode;
int ret = store->ExecuteAndGetString(currentMode, "PRAGMA journal_mode");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentMode, "truncate");
}
/**
* @tc.name: RdbStoreConfig_008
* @tc.desc: test RdbStoreConfig journalMode
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_008, TestSize.Level1)
{
const std::string dbPath = RDB_TEST_PATH + "config_test.db";
RdbStoreConfig config(dbPath, StorageMode::MODE_DISK, false);
config.SetJournalMode(JournalMode::MODE_PERSIST);
std::string journalMode = config.GetJournalMode();
EXPECT_EQ(journalMode, "PERSIST");
ConfigTestOpenCallback helper;
int errCode = E_OK;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
std::string currentMode;
int ret = store->ExecuteAndGetString(currentMode, "PRAGMA journal_mode");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentMode, "persist");
}
/**
* @tc.name: RdbStoreConfig_009
* @tc.desc: test RdbStoreConfig journalMode
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_009, TestSize.Level1)
{
LOG_INFO("RdbStoreConfig_007 start");
const std::string dbPath = RDB_TEST_PATH + "config_test.db";
RdbStoreConfig config(dbPath, StorageMode::MODE_DISK, false);
config.SetJournalMode(JournalMode::MODE_MEMORY);
std::string journalMode = config.GetJournalMode();
EXPECT_EQ(journalMode, "MEMORY");
ConfigTestOpenCallback helper;
int errCode = E_OK;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
std::string currentMode;
int ret = store->ExecuteAndGetString(currentMode, "PRAGMA journal_mode");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentMode, "memory");
}
/**
* @tc.name: RdbStoreConfig_010
* @tc.desc: test RdbStoreConfig journalMode
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_010, TestSize.Level1)
{
const std::string dbPath = RDB_TEST_PATH + "config_test.db";
RdbStoreConfig config(dbPath, StorageMode::MODE_DISK, false);
config.SetJournalMode(JournalMode::MODE_WAL);
std::string journalMode = config.GetJournalMode();
EXPECT_EQ(journalMode, "WAL");
ConfigTestOpenCallback helper;
int errCode = E_OK;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
std::string currentMode;
int ret = store->ExecuteAndGetString(currentMode, "PRAGMA journal_mode");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentMode, "wal");
}
/**
* @tc.name: RdbStoreConfig_011
* @tc.desc: test RdbStoreConfig journalMode
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_011, TestSize.Level1)
{
const std::string dbPath = RDB_TEST_PATH + "config_test.db";
RdbStoreConfig config(dbPath, StorageMode::MODE_DISK, false);
config.SetJournalMode(JournalMode::MODE_OFF);
std::string journalMode = config.GetJournalMode();
EXPECT_EQ(journalMode, "OFF");
ConfigTestOpenCallback helper;
int errCode = E_OK;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
std::string currentMode;
int ret = store->ExecuteAndGetString(currentMode, "PRAGMA journal_mode");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(currentMode, "off");
}

View File

@ -0,0 +1,295 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbStoreInterfaceTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
};
class MyOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
const std::string MyOpenCallback::CREATE_TABLE_TEST = std::string("CREATE TABLE IF NOT EXISTS test ")
+ std::string("(id INTEGER PRIMARY KEY AUTOINCREMENT, name "
"TEXT, "
"age INTEGER, salary REAL, blobType BLOB)");
int MyOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
int MyOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return E_OK;
}
void RdbStoreInterfaceTest::SetUpTestCase(void)
{
}
void RdbStoreInterfaceTest::TearDownTestCase(void)
{
}
void RdbStoreInterfaceTest::SetUp(void)
{
}
void RdbStoreInterfaceTest::TearDown(void)
{
}
/**
* @tc.name: ValueObject_TEST_001
* @tc.desc: test ValueObject
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInterfaceTest, ValueObject_TEST_001, TestSize.Level1)
{
ValueObject obj = ValueObject();
ValueObjectType type = obj.GetType();
EXPECT_EQ(type, ValueObjectType::TYPE_NULL);
}
/**
* @tc.name: ValueObject_TEST_002
* @tc.desc: test ValueObject
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInterfaceTest, ValueObject_TEST_002, TestSize.Level1)
{
int inputVal = 5;
int outputVal = 0;
ValueObject obj = ValueObject(inputVal);
ValueObjectType type = obj.GetType();
EXPECT_EQ(type, ValueObjectType::TYPE_INT);
int ret = obj.GetInt(outputVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(outputVal, 5);
}
/**
* @tc.name: ValueObject_TEST_003
* @tc.desc: test ValueObject
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInterfaceTest, ValueObject_TEST_003, TestSize.Level1)
{
bool inputVal = true;
bool outputVal = false;
ValueObject obj = ValueObject(inputVal);
ValueObjectType type = obj.GetType();
EXPECT_EQ(type, ValueObjectType::TYPE_BOOL);
int ret = obj.GetBool(outputVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(outputVal, true);
}
/**
* @tc.name: ValueObject_TEST_004
* @tc.desc: test ValueObject
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInterfaceTest, ValueObject_TEST_004, TestSize.Level1)
{
std::string inputVal = "hello";
std::string outputVal = "";
ValueObject obj = ValueObject(inputVal);
ValueObjectType type = obj.GetType();
EXPECT_EQ(type, ValueObjectType::TYPE_STRING);
int ret = obj.GetString(outputVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(outputVal, "hello");
}
/**
* @tc.name: ValueObject_TEST_005
* @tc.desc: test ValueObject
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInterfaceTest, ValueObject_TEST_005, TestSize.Level1)
{
std::vector<uint8_t> inputVal = { 'h', 'e', 'l', 'l', 'o' };
std::vector<uint8_t> outputVal;
ValueObject obj = ValueObject(inputVal);
ValueObjectType type = obj.GetType();
EXPECT_EQ(type, ValueObjectType::TYPE_BLOB);
int ret = obj.GetBlob(outputVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(static_cast<int>(outputVal.size()), 5);
EXPECT_EQ(outputVal[0], 'h');
EXPECT_EQ(outputVal[1], 'e');
EXPECT_EQ(outputVal[2], 'l');
EXPECT_EQ(outputVal[3], 'l');
EXPECT_EQ(outputVal[4], 'o');
}
/**
* @tc.name: ValuesBucket_001
* @tc.desc: test ValuesBucket
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInterfaceTest, ValuesBucket_001, TestSize.Level1)
{
ValuesBucket values;
values.PutInt("id", 1);
values.PutNull("name");
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int size = values.Size();
EXPECT_EQ(size, 5);
bool contains = values.HasColumn("name");
EXPECT_EQ(contains, true);
ValueObject obj;
contains = values.GetObject("salary", obj);
double val = 0.0;
ValueObjectType type = obj.GetType();
EXPECT_EQ(type, ValueObjectType::TYPE_DOUBLE);
int ret = obj.GetDouble(val);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(val, 100.5);
values.Delete("name");
size = values.Size();
EXPECT_EQ(size, 4);
contains = values.HasColumn("name");
EXPECT_EQ(contains, false);
values.Clear();
size = values.Size();
EXPECT_EQ(size, 0);
contains = values.HasColumn("salary");
EXPECT_EQ(contains, false);
}
/**
* @tc.name: ValuesBucket_002
* @tc.desc: test ValuesBucket
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInterfaceTest, ValuesBucket_002, TestSize.Level1)
{
int errCode = E_OK;
const std::string dbPath = RDB_TEST_PATH + "InterfaceTest.db";
RdbStoreConfig config(dbPath);
MyOpenCallback helper;
std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
EXPECT_EQ(errCode, E_OK);
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutNull("name");
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
int columnIndex;
std::string strVal;
ret = resultSet->GoToFirstRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = resultSet->GetString(columnIndex, strVal);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ("", strVal);
store = nullptr;
ret = RdbHelper::DeleteRdbStore(dbPath);
EXPECT_EQ(ret, E_OK);
}
/**
* @tc.name: ValuesBucket_003
* @tc.desc: test ValuesBucket
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbStoreInterfaceTest, ValuesBucket_003, TestSize.Level1)
{
ValuesBucket values;
values.PutBool("boolType", true);
values.PutLong("longType", 1);
int size = values.Size();
EXPECT_EQ(size, 2);
bool contains = values.HasColumn("boolType");
EXPECT_EQ(contains, true);
ValueObject obj;
contains = values.GetObject("boolType", obj);
ValueObjectType type = obj.GetType();
EXPECT_EQ(type, ValueObjectType::TYPE_BOOL);
bool val1 = false;
int ret = obj.GetBool(val1);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(val1, true);
contains = values.HasColumn("longType");
EXPECT_EQ(contains, true);
contains = values.GetObject("longType", obj);
type = obj.GetType();
EXPECT_EQ(type, ValueObjectType::TYPE_INT);
int64_t val2 = 0;
ret = obj.GetLong(val2);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(val2, 1);
}

View File

@ -0,0 +1,548 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbTransactionTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
static const std::string DATABASE_NAME;
static std::shared_ptr<RdbStore> store;
static const int E_SQLITE_ERROR; // errno SQLITE_ERROR
};
const std::string RdbTransactionTest::DATABASE_NAME = RDB_TEST_PATH + "transaction_test.db";
std::shared_ptr<RdbStore> RdbTransactionTest::store = nullptr;
const int RdbTransactionTest::E_SQLITE_ERROR = -1; // errno SQLITE_ERROR
class TransactionTestOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
const std::string TransactionTestOpenCallback::CREATE_TABLE_TEST = std::string("CREATE TABLE IF NOT EXISTS test ")
+ std::string("(id INTEGER PRIMARY KEY "
"AUTOINCREMENT, name TEXT NOT NULL, "
"age INTEGER, salary REAL, blobType "
"BLOB)");
int TransactionTestOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
int TransactionTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return E_OK;
}
void RdbTransactionTest::SetUpTestCase(void)
{
int errCode = E_OK;
RdbStoreConfig config(RdbTransactionTest::DATABASE_NAME);
TransactionTestOpenCallback helper;
RdbTransactionTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(RdbTransactionTest::store, nullptr);
EXPECT_EQ(errCode, E_OK);
}
void RdbTransactionTest::TearDownTestCase(void)
{
RdbHelper::DeleteRdbStore(RdbTransactionTest::DATABASE_NAME);
}
void RdbTransactionTest::SetUp(void)
{
store->ExecuteSql("DELETE FROM test");
}
void RdbTransactionTest::TearDown(void)
{
}
/**
* @tc.name: RdbStore_Transaction_001
* @tc.desc: test RdbStore Transaction
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbTransactionTest, RdbStore_Transaction_001, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbTransactionTest::store;
int64_t id;
ValuesBucket values;
int ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
ret = store->MarkAsCommit();
EXPECT_EQ(ret, E_OK);
ret = store->EndTransaction();
EXPECT_EQ(ret, E_OK);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 3);
int deletedRows;
ret = store->Delete(deletedRows, "test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(deletedRows, 3);
}
/**
* @tc.name: RdbStore_Transaction_002
* @tc.desc: test RdbStore Transaction
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbTransactionTest, RdbStore_Transaction_002, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbTransactionTest::store;
int64_t id;
ValuesBucket values;
int ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
ret = store->EndTransaction();
EXPECT_EQ(ret, E_OK);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 0);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
int deletedRows;
ret = store->Delete(deletedRows, "test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(deletedRows, 0);
}
/**
* @tc.name: RdbStore_NestedTransaction_001
* @tc.desc: test RdbStore Transaction
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbTransactionTest, RdbStore_NestedTransaction_001, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbTransactionTest::store;
int64_t id;
ValuesBucket values;
int ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
ret = store->EndTransaction(); // not commit
EXPECT_EQ(ret, E_OK);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
ret = store->MarkAsCommit();
EXPECT_EQ(ret, E_OK);
ret = store->EndTransaction();
EXPECT_EQ(ret, E_OK);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 0);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
int deletedRows;
ret = store->Delete(deletedRows, "test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(deletedRows, 0);
}
/**
* @tc.name: RdbStore_NestedTransaction_002
* @tc.desc: test RdbStore Transaction
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbTransactionTest, RdbStore_NestedTransaction_002, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbTransactionTest::store;
int64_t id;
ValuesBucket values;
int ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
ret = store->MarkAsCommit();
EXPECT_EQ(ret, E_OK);
ret = store->EndTransaction(); // commit
EXPECT_EQ(ret, E_OK);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
ret = store->EndTransaction(); // not commit
EXPECT_EQ(ret, E_OK);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 0);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
int deletedRows;
ret = store->Delete(deletedRows, "test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(deletedRows, 0);
}
/**
* @tc.name: RdbStore_NestedTransaction_003
* @tc.desc: test RdbStore Transaction
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbTransactionTest, RdbStore_NestedTransaction_003, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbTransactionTest::store;
int64_t id;
ValuesBucket values;
int ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
ret = store->EndTransaction(); // not commit
EXPECT_EQ(ret, E_OK);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
ret = store->EndTransaction(); // not commit
EXPECT_EQ(ret, E_OK);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 0);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
int deletedRows;
ret = store->Delete(deletedRows, "test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(deletedRows, 0);
}
/**
* @tc.name: RdbStore_NestedTransaction_004
* @tc.desc: test RdbStore Transaction
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbTransactionTest, RdbStore_NestedTransaction_004, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbTransactionTest::store;
int64_t id;
ValuesBucket values;
int ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
ret = store->MarkAsCommit();
EXPECT_EQ(ret, E_OK);
ret = store->EndTransaction(); // commit
EXPECT_EQ(ret, E_OK);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
ret = store->MarkAsCommit();
EXPECT_EQ(ret, E_OK);
ret = store->EndTransaction(); // commit
EXPECT_EQ(ret, E_OK);
int64_t count;
ret = store->ExecuteAndGetLong(count, "SELECT COUNT(*) FROM test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(count, 3);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
int deletedRows;
ret = store->Delete(deletedRows, "test");
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(deletedRows, 3);
}
/**
* @tc.name: RdbStore_Transaction_003
* @tc.desc: test RdbStore Transaction
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: chenxi
*/
HWTEST_F(RdbTransactionTest, RdbStore_Transaction_003, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbTransactionTest::store;
bool in = store->IsInTransaction();
EXPECT_EQ(in, false);
int ret = store->BeginTransaction();
EXPECT_EQ(ret, E_OK);
in = store->IsInTransaction();
EXPECT_EQ(in, true);
ret = store->MarkAsCommit();
EXPECT_EQ(ret, E_OK);
ret = store->EndTransaction();
EXPECT_EQ(ret, E_OK);
in = store->IsInTransaction();
EXPECT_EQ(in, false);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,203 @@
/*
* Copyright (c) 2021 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 <gtest/gtest.h>
#include <string>
#include "common.h"
#include "logger.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
class RdbUpgradeTest : public testing::Test {
public:
static void SetUpTestCase(void);
static void TearDownTestCase(void);
void SetUp();
void TearDown();
void InsertValues(std::shared_ptr<RdbStore> &store);
static const std::string DATABASE_NAME;
static std::shared_ptr<RdbStore> store;
};
const std::string RdbUpgradeTest::DATABASE_NAME = RDB_TEST_PATH + "upgrade_test.db";
std::shared_ptr<RdbStore> RdbUpgradeTest::store = nullptr;
class UpgradeTestOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string CREATE_TABLE_TEST;
};
std::string const UpgradeTestOpenCallback::CREATE_TABLE_TEST = std::string("CREATE TABLE IF NOT EXISTS test ")
+ std::string("(id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name TEXT NOT NULL, age INTEGER, salary "
"REAL, blobType BLOB)");
int UpgradeTestOpenCallback::OnCreate(RdbStore &store)
{
return store.ExecuteSql(CREATE_TABLE_TEST);
}
int UpgradeTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return E_OK;
}
class UpgradeOpenCallback : public RdbOpenCallback {
public:
int OnCreate(RdbStore &rdbStore) override;
int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override;
static const std::string UPGRADE_TABLE_TEST;
};
std::string const UpgradeOpenCallback::UPGRADE_TABLE_TEST = std::string("ALTER TABLE test ADD COLUMN address TEXT;");
int UpgradeOpenCallback::OnCreate(RdbStore &store)
{
return E_OK;
}
int UpgradeOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
return store.ExecuteSql(UPGRADE_TABLE_TEST);
}
void RdbUpgradeTest::SetUpTestCase(void)
{
int errCode = E_OK;
RdbStoreConfig config(RdbUpgradeTest::DATABASE_NAME);
UpgradeTestOpenCallback helper;
RdbUpgradeTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(RdbUpgradeTest::store, nullptr);
}
void RdbUpgradeTest::TearDownTestCase(void)
{
RdbHelper::DeleteRdbStore(RdbUpgradeTest::DATABASE_NAME);
}
void RdbUpgradeTest::SetUp(void)
{
store->ExecuteSql("DELETE FROM test");
}
void RdbUpgradeTest::TearDown(void)
{
}
/**
* @tc.name: RdbStore_Upgrade_001
* @tc.desc: test RdbStore upgrade
* @tc.type: FUNC
* @tc.require: AR000CU2BO
* @tc.author: liumengyue
*/
HWTEST_F(RdbUpgradeTest, RdbStore_Upgrade_001, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbUpgradeTest::store;
RdbUpgradeTest::InsertValues(store);
std::unique_ptr<ResultSet> resultSet = store->QuerySql("SELECT * FROM test");
EXPECT_NE(resultSet, nullptr);
int ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
ret = resultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = resultSet->Close();
EXPECT_EQ(ret, E_OK);
int errCode = E_OK;
RdbStoreConfig config(RdbUpgradeTest::DATABASE_NAME);
UpgradeOpenCallback callBack;
std::shared_ptr<RdbStore> upgradeStore = RdbHelper::GetRdbStore(config, 2, callBack, errCode);
EXPECT_NE(upgradeStore, nullptr);
std::unique_ptr<ResultSet> upgradeResultSet = upgradeStore->QuerySql("SELECT * FROM test");
EXPECT_NE(upgradeResultSet, nullptr);
int columnCount;
ret = upgradeResultSet->GetColumnCount(columnCount);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(columnCount, 6);
ret = upgradeResultSet->GoToNextRow();
int columnIndex;
ret = upgradeResultSet->GetColumnIndexForName("id", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = upgradeResultSet->GetColumnIndexForName("name", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = upgradeResultSet->GetColumnIndexForName("age", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = upgradeResultSet->GetColumnIndexForName("salary", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = upgradeResultSet->GetColumnIndexForName("blobType", columnIndex);
EXPECT_EQ(ret, E_OK);
ret = upgradeResultSet->GetColumnIndexForName("address", columnIndex);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(columnIndex, 5);
ret = upgradeResultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
ret = upgradeResultSet->GoToNextRow();
EXPECT_EQ(ret, E_OK);
ret = upgradeResultSet->GoToNextRow();
EXPECT_EQ(ret, E_STEP_RESULT_IS_AFTER_LASET);
ret = upgradeResultSet->Close();
EXPECT_EQ(ret, E_OK);
}
void RdbUpgradeTest::InsertValues(std::shared_ptr<RdbStore> &store)
{
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 18);
values.PutDouble("salary", 100.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(1, id);
values.Clear();
values.PutInt("id", 2);
values.PutString("name", std::string("lisi"));
values.PutInt("age", 19);
values.PutDouble("salary", 200.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 4, 5, 6 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(2, id);
values.Clear();
values.PutInt("id", 3);
values.PutString("name", std::string("wangyjing"));
values.PutInt("age", 20);
values.PutDouble("salary", 300.5);
values.PutBlob("blobType", std::vector<uint8_t>{ 7, 8, 9 });
ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
EXPECT_EQ(3, id);
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_JSKIT_COMMON_H
#define PREFERENCES_JSKIT_COMMON_H
#include <string>
#include <vector>
#include "hilog/log.h"
#include "preferences_errno.h"
namespace OHOS {
namespace PreferencesJsKit {
static const OHOS::HiviewDFX::HiLogLabel PREFIX_LABEL = { LOG_CORE, 0xD001650, "PreferencesJsKit" };
#define LOG_DEBUG(...) ((void)OHOS::HiviewDFX::HiLog::Debug(PREFIX_LABEL, __VA_ARGS__))
#define LOG_INFO(...) ((void)OHOS::HiviewDFX::HiLog::Info(PREFIX_LABEL, __VA_ARGS__))
#define LOG_WARN(...) ((void)OHOS::HiviewDFX::HiLog::Warn(PREFIX_LABEL, __VA_ARGS__))
#define LOG_ERROR(...) ((void)OHOS::HiviewDFX::HiLog::Error(PREFIX_LABEL, __VA_ARGS__))
#define LOG_FATAL(...) ((void)OHOS::HiviewDFX::HiLog::Fatal(PREFIX_LABEL, __VA_ARGS__))
static const std::vector<std::string> ERR_INFO {
"E_ERROR",
"E_STALE",
"E_INVALID_ARGS",
"E_OUT_OF_MEMORY",
"E_NOT_PERMIT",
"E_KEY_EMPTY",
"E_KEY_EXCEED_MAX_LENGTH",
"E_PTR_EXIST_ANOTHER_HOLD",
"E_DELETE_FILE_FAIL",
"E_EMPTY_FILE_PATH",
"E_RELATIVE_PATH",
"E_EMPTY_FILE_NAME",
"E_INVALID_FILE_PATH",
"E_PATH_EXCEED_MAX_LENGTH"
};
static inline const char *GetErrStr(int err)
{
if (err == OHOS::NativePreferences::E_OK) {
return nullptr;
}
size_t index = err - OHOS::NativePreferences::E_BASE - 1;
if (index >= ERR_INFO.size() || index < 0) {
return "Unknown error";
}
return ERR_INFO.at(index).c_str();
}
} // namespace PreferencesJsKit
} // namespace OHOS
#endif

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2021 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 <stdio.h>
#include <string.h>
#include <unistd.h>
#include "napi/native_api.h"
#include "napi/native_node_api.h"
#include "napi_preference.h"
#include "napi_preference_helper.h"
using namespace OHOS::PreferencesJsKit;
EXTERN_C_START
/*
* function for module exports
*/
static napi_value Init(napi_env env, napi_value exports)
{
PreferencesProxy::Init(env, exports);
InitPreferenceHelper(env, exports);
return exports;
}
EXTERN_C_END
/*
* Module define
*/
static napi_module _module = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "data.storage",
.nm_priv = ((void *)0),
.reserved = { 0 }
};
/*
* Module register function
*/
extern "C" __attribute__((constructor)) void RegisterModule(void)
{
napi_module_register(&_module);
}

View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_JSKIT_NAPI_ASYNC_PROXY_H
#define PREFERENCES_JSKIT_NAPI_ASYNC_PROXY_H
#include <vector>
#include "securec.h"
#include "napi/native_common.h"
#include "napi/native_api.h"
#include "napi/native_node_api.h"
#include "common.h"
namespace OHOS {
namespace PreferencesJsKit {
constexpr int MAX_INPUT_COUNT = 10;
constexpr int OK = 0;
constexpr int ERR = -1;
// T inherits AysncContext
template<class T>
class NapiAsyncProxy {
public:
using InputParser = void (*)(const napi_env&, const napi_value&, T*);
using NapiAsyncExecute = int (*)(T*);
using NapiAsyncComplete = int (*)(T*, napi_value&);
// AsyncContext base
struct AysncContext {
napi_env env;
napi_callback_info info;
napi_async_work work;
napi_deferred deferred;
napi_ref callbackRef;
NapiAsyncExecute execFunc;
int execStatus;
NapiAsyncComplete completeFunc;
void* boundObj;
};
public:
void Init(napi_env env, napi_callback_info info)
{
asyncContext = new T();
if (asyncContext == nullptr) {
LOG_ERROR("new AsyncContext failed");
return;
}
memset_s(asyncContext, sizeof(T), 0, sizeof(T));
asyncContext->env = env;
asyncContext->info = info;
}
void ParseInputs(std::vector<InputParser>& parsers)
{
if (asyncContext == nullptr) {
LOG_ERROR("uninitialized AsyncContext");
return;
}
LOG_DEBUG("ParseInputs parsers num: %{public}zu", parsers.size());
napi_value thisObj = nullptr;
size_t argc = parsers.size() + 1;
napi_value args[MAX_INPUT_COUNT] = { 0 };
napi_get_cb_info(asyncContext->env, asyncContext->info, &argc, args, &thisObj, nullptr);
LOG_DEBUG("ParseInputs real num:%{public}zu", argc);
for (size_t i = 0; i < argc && argc <= MAX_INPUT_COUNT; i++) {
if (i >= parsers.size()) {
// determines whether the last parameter is a callback function.
napi_valuetype valueType = napi_undefined;
napi_typeof(asyncContext->env, args[i], &valueType);
if (valueType == napi_function) {
napi_create_reference(asyncContext->env, args[i], 1, &asyncContext->callbackRef);
}
break;
}
auto* parserFunction = parsers[i];
if (parserFunction != nullptr) {
parserFunction(asyncContext->env, args[i], this->asyncContext);
}
}
napi_unwrap(asyncContext->env, thisObj, &asyncContext->boundObj);
}
napi_value DoAsyncWork(std::string resourceName, NapiAsyncExecute execFunc, NapiAsyncComplete completeFunc)
{
if (asyncContext == nullptr) {
LOG_ERROR("uninitialized AsyncContext");
return nullptr;
}
LOG_DEBUG("DoAsyncWork resource name:%{public}s", resourceName.c_str());
napi_value ret = nullptr;
if (asyncContext->callbackRef == nullptr) {
napi_create_promise(asyncContext->env, &asyncContext->deferred, &ret);
} else {
napi_get_undefined(asyncContext->env, &ret);
}
napi_value resource = nullptr;
napi_create_string_utf8(asyncContext->env, resourceName.c_str(), NAPI_AUTO_LENGTH, &resource);
asyncContext->execFunc = execFunc;
asyncContext->completeFunc = completeFunc;
napi_create_async_work(
asyncContext->env,
nullptr,
resource,
[](napi_env env, void* data) {
LOG_DEBUG("execute callback begin");
T* asyncContext = (T*)data;
asyncContext->execStatus = asyncContext->execFunc(asyncContext);
LOG_DEBUG("execute callback end, ret:%{public}d", asyncContext->execStatus);
},
[](napi_env env, napi_status status, void* data) {
T* asyncContext = (T*)data;
napi_value output = nullptr;
LOG_DEBUG("complete callback begin");
int completeStatus = asyncContext->completeFunc(asyncContext, output);
LOG_DEBUG("complete callback end, ret:%{public}d", completeStatus);
napi_value result[RESULT_COUNT] = { 0 };
if (asyncContext->execStatus == OK && completeStatus == OK) {
napi_get_undefined(env, &result[0]);
result[1] = output;
} else {
napi_value message = nullptr;
napi_create_string_utf8(env, "async call failed", NAPI_AUTO_LENGTH, &message);
napi_create_error(env, nullptr, message, &result[0]);
napi_get_undefined(env, &result[1]);
}
if (asyncContext->deferred) {
// promise
if (asyncContext->execStatus == OK && completeStatus == OK) {
napi_resolve_deferred(env, asyncContext->deferred, result[1]);
} else {
napi_reject_deferred(env, asyncContext->deferred, result[0]);
}
} else {
// callback
napi_value callback = nullptr;
napi_get_reference_value(env, asyncContext->callbackRef, &callback);
napi_value callbackResult = nullptr;
napi_status status =
napi_call_function(env, nullptr, callback, RESULT_COUNT, result, &callbackResult);
napi_delete_reference(env, asyncContext->callbackRef);
LOG_DEBUG("callback function execution status: %{public}d", status);
}
napi_delete_async_work(env, asyncContext->work);
delete asyncContext;
},
(void*)asyncContext,
&asyncContext->work);
napi_queue_async_work(asyncContext->env, asyncContext->work);
return ret;
}
private:
T* asyncContext;
constexpr static int RESULT_COUNT = 2;
};
} // namespace PreferencesJsKit
} // namespace OHOS
#endif

View File

@ -0,0 +1,628 @@
/*
* Copyright (c) 2021 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_preference.h"
#include <cerrno>
#include <cmath>
#include <limits>
#include "securec.h"
#include "common.h"
#include "preferences.h"
#include "preferences_errno.h"
#include "preferences_value.h"
#include "napi_async_proxy.h"
using namespace OHOS::NativePreferences;
namespace OHOS {
namespace PreferencesJsKit {
#define MAX_KEY_LENGTH Preferences::MAX_KEY_LENGTH
#define MAX_VALUE_LENGTH Preferences::MAX_VALUE_LENGTH
struct StorageAysncContext : NapiAsyncProxy<StorageAysncContext>::AysncContext {
std::string key;
PreferencesValue defValue = PreferencesValue((int)0);
bool hasKey;
};
napi_ref PreferencesProxy::constructor;
PreferencesProxy::PreferencesProxy(std::shared_ptr<OHOS::NativePreferences::Preferences> value)
: value_(value), env_(nullptr), wrapper_(nullptr)
{}
PreferencesProxy::~PreferencesProxy()
{
napi_delete_reference(env_, wrapper_);
}
void PreferencesProxy::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
{
LOG_DEBUG("Destructor");
PreferencesProxy *obj = static_cast<PreferencesProxy *>(nativeObject);
delete obj;
}
void PreferencesProxy::Init(napi_env env, napi_value exports)
{
napi_property_descriptor descriptors[] = {
DECLARE_NAPI_FUNCTION("putSync", SetValueSync), DECLARE_NAPI_FUNCTION("put", SetValue),
DECLARE_NAPI_FUNCTION("getSync", GetValueSync), DECLARE_NAPI_FUNCTION("get", GetValue),
DECLARE_NAPI_FUNCTION("deleteSync", DeleteSync), DECLARE_NAPI_FUNCTION("delete", Delete),
DECLARE_NAPI_FUNCTION("clearSync", ClearSync), DECLARE_NAPI_FUNCTION("clear", Clear),
DECLARE_NAPI_FUNCTION("hasSync", HasKeySync), DECLARE_NAPI_FUNCTION("has", HasKey),
DECLARE_NAPI_FUNCTION("flushSync", FlushSync), DECLARE_NAPI_FUNCTION("flush", Flush),
DECLARE_NAPI_FUNCTION("on", RegisterObserver), DECLARE_NAPI_FUNCTION("off", UnRegisterObserver),
};
LOG_DEBUG("Init");
napi_value cons = nullptr;
napi_define_class(env, "Storage", NAPI_AUTO_LENGTH, New, nullptr,
sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &cons);
napi_create_reference(env, cons, 1, &constructor);
LOG_DEBUG("Init end");
}
napi_status PreferencesProxy::NewInstance(napi_env env, napi_value arg, napi_value *instance)
{
napi_status status;
const int argc = 1;
napi_value argv[argc] = {arg};
napi_value cons;
status = napi_get_reference_value(env, constructor, &cons);
if (status != napi_ok) {
return status;
}
status = napi_new_instance(env, cons, argc, argv, instance);
if (status != napi_ok) {
return status;
}
return napi_ok;
}
napi_value PreferencesProxy::New(napi_env env, napi_callback_info info)
{
LOG_DEBUG("New");
size_t argc = 1;
napi_value args[1] = {0};
napi_value _this = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
if (_this == nullptr) {
LOG_WARN("get this failed");
return nullptr;
}
napi_valuetype valueType = napi_undefined;
NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
NAPI_ASSERT(env, valueType == napi_string, "input type not string");
char *path = new char[PATH_MAX];
memset_s(path, PATH_MAX, 0, PATH_MAX);
size_t pathLen = 0;
napi_status status = napi_get_value_string_utf8(env, args[0], path, PATH_MAX, &pathLen);
if (status != napi_ok) {
LOG_ERROR("get path failed. ");
delete[] path;
return nullptr;
}
// get native object
int errCode = 0;
std::shared_ptr<OHOS::NativePreferences::Preferences> preference =
OHOS::NativePreferences::PreferencesHelper::GetPreferences(path, errCode);
delete[] path;
NAPI_ASSERT(env, preference != nullptr, "failed to call native");
PreferencesProxy *obj = new PreferencesProxy(preference);
obj->env_ = env;
NAPI_CALL(env, napi_wrap(env, _this, obj, PreferencesProxy::Destructor,
nullptr, // finalize_hint
&obj->wrapper_));
LOG_DEBUG("New end");
return _this;
}
template<typename T>
bool CheckNumberType(double input)
{
if (input > (std::numeric_limits<T>::max)() || input < (std::numeric_limits<T>::min)()) {
return false;
}
return true;
}
bool IsFloat(double input)
{
return abs(input - floor(input)) >= DBL_EPSILON;
}
napi_value PreferencesProxy::GetValueSync(napi_env env, napi_callback_info info)
{
napi_value _this = nullptr;
size_t argc = 2; // arg count
napi_value args[2] = {0};
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
NAPI_ASSERT(env, argc == 2, "Wrong number of arguments");
// get value type
napi_valuetype valueType = napi_undefined;
NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
// get input key
char key[MAX_KEY_LENGTH] = {0};
size_t keySize = 0;
NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &keySize));
PreferencesProxy *obj = nullptr;
NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
NAPI_ASSERT(env, (obj != nullptr && obj->value_ != nullptr), "unwrap null native pointer");
napi_value output = nullptr;
NAPI_CALL(env, napi_typeof(env, args[1], &valueType));
if (valueType == napi_number) {
double value;
NAPI_CALL(env, napi_get_value_double(env, args[1], &value));
LOG_DEBUG("get number");
if (!IsFloat(value)) {
int64_t result = obj->value_->GetLong(key, (int64_t)value);
NAPI_CALL(env, napi_create_int64(env, result, &output)); // int
} else {
float result = obj->value_->GetFloat(key, value);
NAPI_CALL(env, napi_create_double(env, result, &output)); // double
}
LOG_DEBUG("get number end");
} else if (valueType == napi_string) {
LOG_DEBUG("get string");
char *value = new char[MAX_VALUE_LENGTH];
size_t valueSize = 0;
napi_get_value_string_utf8(env, args[1], value, MAX_VALUE_LENGTH, &valueSize);
// get value
std::string result = obj->value_->GetString(key, value);
delete[] value;
NAPI_CALL(env, napi_create_string_utf8(env, result.c_str(), result.size(), &output));
LOG_DEBUG("get string end");
} else if (valueType == napi_boolean) {
LOG_DEBUG("get bool");
bool value = false;
NAPI_CALL(env, napi_get_value_bool(env, args[1], &value));
// get value
bool result = obj->value_->GetBool(key, value);
NAPI_CALL(env, napi_get_boolean(env, result, &output));
LOG_DEBUG("get bool end");
} else {
NAPI_ASSERT(env, false, "Wrong second parameter type");
}
return output;
}
void ParseKey(const napi_env& env, const napi_value& arg, StorageAysncContext* asyncContext)
{
// get input key
char key[MAX_KEY_LENGTH] = { 0 };
size_t keySize = 0;
napi_get_value_string_utf8(env, arg, key, MAX_KEY_LENGTH, &keySize);
asyncContext->key = key;
}
void ParseDefValue(const napi_env& env, const napi_value& arg, StorageAysncContext* asyncContext)
{
napi_valuetype valueType = napi_undefined;
napi_typeof(env, arg, &valueType);
if (valueType == napi_number) {
double number;
napi_get_value_double(env, arg, &number);
if (!IsFloat(number)) {
PreferencesValue value((int64_t)number);
asyncContext->defValue = value;
} else {
PreferencesValue value((float)number);
asyncContext->defValue = value;
}
} else if (valueType == napi_string) {
char* str = new char[MAX_VALUE_LENGTH];
size_t valueSize = 0;
napi_get_value_string_utf8(env, arg, str, MAX_VALUE_LENGTH, &valueSize);
PreferencesValue value((std::string)(str));
asyncContext->defValue = value;
delete[] str;
} else if (valueType == napi_boolean) {
bool bValue = false;
napi_get_value_bool(env, arg, &bValue);
PreferencesValue value((bool)(bValue));
asyncContext->defValue = value;
} else {
LOG_ERROR("Wrong second parameter type");
}
}
napi_value PreferencesProxy::GetValue(napi_env env, napi_callback_info info)
{
NapiAsyncProxy<StorageAysncContext> proxy;
proxy.Init(env, info);
std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
parsers.push_back(ParseKey);
parsers.push_back(ParseDefValue);
proxy.ParseInputs(parsers);
return proxy.DoAsyncWork(
"GetValue",
[](StorageAysncContext* asyncContext) {
int errCode = OK;
PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
if (asyncContext->defValue.IsBool()) {
bool tmpValue = (bool)obj->value_->GetBool(asyncContext->key, (bool)asyncContext->defValue);
asyncContext->defValue = PreferencesValue((bool)tmpValue);
} else if (asyncContext->defValue.IsLong()) {
int64_t tmpValue = obj->value_->GetLong(asyncContext->key, (int64_t)asyncContext->defValue);
asyncContext->defValue = PreferencesValue((int64_t)tmpValue);
} else if (asyncContext->defValue.IsString()) {
std::string tmpValue = obj->value_->GetString(asyncContext->key, (std::string)asyncContext->defValue);
asyncContext->defValue = PreferencesValue((std::string)tmpValue);
} else if (asyncContext->defValue.IsFloat()) {
float tmpValue = obj->value_->GetFloat(asyncContext->key, (float)asyncContext->defValue);
asyncContext->defValue = PreferencesValue((float)tmpValue);
} else {
errCode = ERR;
}
return errCode;
},
[](StorageAysncContext* asyncContext, napi_value& output) {
int errCode = OK;
if (asyncContext->defValue.IsBool()) {
napi_get_boolean(asyncContext->env, (bool)asyncContext->defValue, &output);
} else if (asyncContext->defValue.IsLong()) {
napi_create_int64(asyncContext->env, (int64_t)asyncContext->defValue, &output);
} else if (asyncContext->defValue.IsString()) {
std::string tempStr = (std::string)asyncContext->defValue;
napi_create_string_utf8(asyncContext->env, tempStr.c_str(), tempStr.size(), &output);
} else if (asyncContext->defValue.IsFloat()) {
napi_create_double(asyncContext->env, (float)asyncContext->defValue, &output);
} else {
errCode = ERR;
}
return errCode;
});
}
napi_value PreferencesProxy::SetValueSync(napi_env env, napi_callback_info info)
{
napi_value _this = nullptr;
size_t argc = 2;
napi_value args[2] = {0};
LOG_DEBUG("SETVALUE");
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
NAPI_ASSERT(env, argc == 2, "Wrong number of arguments");
// get value type
napi_valuetype valueType = napi_undefined;
NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
// get input key
char key[MAX_KEY_LENGTH] = {0};
size_t out = 0;
NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &out));
PreferencesProxy *obj = nullptr;
NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
NAPI_ASSERT(env, (obj != nullptr && obj->value_ != nullptr), "unwrap null native pointer");
NAPI_CALL(env, napi_typeof(env, args[1], &valueType));
if (valueType == napi_number) {
double value = 0.0;
NAPI_CALL(env, napi_get_value_double(env, args[1], &value));
if (IsFloat(value)) {
NAPI_ASSERT(env, CheckNumberType<float>(value), "the value out of float range");
int result = obj->value_->PutFloat(key, (float)value);
NAPI_ASSERT(env, result == E_OK, "call PutFloat failed");
} else {
NAPI_ASSERT(env, CheckNumberType<int64_t>(value), "the value out of long long range");
int result = obj->value_->PutLong(key, (int64_t)value);
NAPI_ASSERT(env, result == E_OK, "call PutLong failed");
}
} else if (valueType == napi_string) {
char *value = new char[MAX_VALUE_LENGTH];
napi_get_value_string_utf8(env, args[1], value, MAX_VALUE_LENGTH, &out);
// get value
int result = obj->value_->PutString(key, value);
delete[] value;
NAPI_ASSERT(env, result == E_OK, "call PutString failed");
} else if (valueType == napi_boolean) {
bool value = false;
NAPI_CALL(env, napi_get_value_bool(env, args[1], &value));
// get value
int result = obj->value_->PutBool(key, value);
NAPI_ASSERT(env, result == E_OK, "call PutBool failed");
} else {
NAPI_ASSERT(env, false, "Wrong second parameter type");
}
return nullptr;
}
napi_value PreferencesProxy::SetValue(napi_env env, napi_callback_info info)
{
NapiAsyncProxy<StorageAysncContext> proxy;
proxy.Init(env, info);
std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
parsers.push_back(ParseKey);
parsers.push_back(ParseDefValue);
proxy.ParseInputs(parsers);
return proxy.DoAsyncWork(
"SetValue",
[](StorageAysncContext* asyncContext) {
int errCode = OK;
PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
if (asyncContext->defValue.IsBool()) {
errCode = obj->value_->PutBool(asyncContext->key, (bool)asyncContext->defValue);
} else if (asyncContext->defValue.IsLong()) {
errCode = obj->value_->PutLong(asyncContext->key, (int64_t)asyncContext->defValue);
} else if (asyncContext->defValue.IsString()) {
errCode = obj->value_->PutString(asyncContext->key, (std::string)asyncContext->defValue);
} else if (asyncContext->defValue.IsFloat()) {
errCode = obj->value_->PutFloat(asyncContext->key, (float)asyncContext->defValue);
} else {
errCode = ERR;
}
return errCode;
},
[](StorageAysncContext* asyncContext, napi_value& output) {
napi_status status = napi_get_undefined(asyncContext->env, &output);
return (status == napi_ok) ? OK : ERR;
});
}
napi_value PreferencesProxy::DeleteSync(napi_env env, napi_callback_info info)
{
napi_value _this = nullptr;
size_t argc = 1;
napi_value args[1] = {0};
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
// get value type
napi_valuetype valueType;
NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
char key[MAX_KEY_LENGTH] = {0};
size_t out = 0;
NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &out));
PreferencesProxy *obj = nullptr;
NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
int result = obj->value_->Delete(key);
NAPI_ASSERT(env, result == E_OK, "call Delete failed");
LOG_INFO("Delete");
return nullptr;
}
napi_value PreferencesProxy::Delete(napi_env env, napi_callback_info info)
{
NapiAsyncProxy<StorageAysncContext> proxy;
proxy.Init(env, info);
std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
parsers.push_back(ParseKey);
proxy.ParseInputs(parsers);
return proxy.DoAsyncWork(
"Delete",
[](StorageAysncContext* asyncContext) {
PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
int errCode = obj->value_->Delete(asyncContext->key);
return errCode;
},
[](StorageAysncContext* asyncContext, napi_value& output) {
napi_status status = napi_get_undefined(asyncContext->env, &output);
return (status == napi_ok) ? OK : ERR;
});
}
napi_value PreferencesProxy::HasKeySync(napi_env env, napi_callback_info info)
{
napi_value _this = nullptr;
size_t argc = 1;
napi_value args[1] = {0};
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
// get value type
napi_valuetype valueType;
NAPI_CALL(env, napi_typeof(env, args[0], &valueType));
NAPI_ASSERT(env, valueType == napi_string, "type mismatch for key");
char key[MAX_KEY_LENGTH] = {0};
size_t out = 0;
NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], key, MAX_KEY_LENGTH, &out));
PreferencesProxy *obj = nullptr;
NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
bool result = obj->value_->HasKey(key);
napi_value output = nullptr;
NAPI_CALL(env, napi_get_boolean(env, result, &output));
LOG_DEBUG("HasKey");
return output;
}
napi_value PreferencesProxy::HasKey(napi_env env, napi_callback_info info)
{
NapiAsyncProxy<StorageAysncContext> proxy;
proxy.Init(env, info);
std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
parsers.push_back(ParseKey);
proxy.ParseInputs(parsers);
return proxy.DoAsyncWork(
"HasKey",
[](StorageAysncContext* asyncContext) {
PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
asyncContext->hasKey = obj->value_->HasKey(asyncContext->key);
return OK;
},
[](StorageAysncContext* asyncContext, napi_value& output) {
napi_status status = napi_get_boolean(asyncContext->env, asyncContext->hasKey, &output);
return (status == napi_ok) ? OK : ERR;
});
}
napi_value PreferencesProxy::Flush(napi_env env, napi_callback_info info)
{
NapiAsyncProxy<StorageAysncContext> proxy;
proxy.Init(env, info);
std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
parsers.push_back(ParseKey);
proxy.ParseInputs(parsers);
return proxy.DoAsyncWork(
"Flush",
[](StorageAysncContext* asyncContext) {
PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
obj->value_->Flush();
return OK;
},
[](StorageAysncContext* asyncContext, napi_value& output) {
napi_status status = napi_get_undefined(asyncContext->env, &output);
return (status == napi_ok) ? OK : ERR;
});
}
napi_value PreferencesProxy::FlushSync(napi_env env, napi_callback_info info)
{
napi_value _this = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &_this, nullptr));
PreferencesProxy *obj = nullptr;
NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
int result = obj->value_->FlushSync();
napi_value output = nullptr;
NAPI_CALL(env, napi_create_int64(env, result, &output));
LOG_DEBUG("FlushSync");
return output;
}
napi_value PreferencesProxy::ClearSync(napi_env env, napi_callback_info info)
{
napi_value _this = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &_this, nullptr));
PreferencesProxy *obj = nullptr;
NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
int result = obj->value_->Clear();
NAPI_ASSERT(env, result == E_OK, "call Clear failed");
LOG_DEBUG("Clear");
return nullptr;
}
napi_value PreferencesProxy::Clear(napi_env env, napi_callback_info info)
{
NapiAsyncProxy<StorageAysncContext> proxy;
proxy.Init(env, info);
std::vector<NapiAsyncProxy<StorageAysncContext>::InputParser> parsers;
proxy.ParseInputs(parsers);
return proxy.DoAsyncWork(
"Clear",
[](StorageAysncContext* asyncContext) {
PreferencesProxy* obj = reinterpret_cast<PreferencesProxy*>(asyncContext->boundObj);
return obj->value_->Clear();
},
[](StorageAysncContext* asyncContext, napi_value& output) {
napi_status status = napi_get_undefined(asyncContext->env, &output);
return (status == napi_ok) ? OK : ERR;
});
}
napi_value PreferencesProxy::RegisterObserver(napi_env env, napi_callback_info info)
{
napi_value _this = nullptr;
size_t argc = 2;
napi_value args[2] = {0};
LOG_DEBUG("RegisterObserver");
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
napi_valuetype type;
NAPI_CALL(env, napi_typeof(env, args[0], &type));
NAPI_ASSERT(env, type == napi_string, "key not string type");
NAPI_CALL(env, napi_typeof(env, args[1], &type));
NAPI_ASSERT(env, type == napi_function, "observer not function type");
PreferencesProxy *obj = nullptr;
NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
// reference保存
obj->observer_ = std::make_shared<PreferencesObserverImpl>(env, args[1]);
obj->value_->RegisterObserver(obj->observer_);
LOG_DEBUG("RegisterObserver end");
return nullptr;
}
napi_value PreferencesProxy::UnRegisterObserver(napi_env env, napi_callback_info info)
{
napi_value _this = nullptr;
size_t argc = 2;
napi_value args[2] = {0};
LOG_DEBUG("UnRegisterObserver");
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
napi_valuetype type;
NAPI_CALL(env, napi_typeof(env, args[0], &type));
NAPI_ASSERT(env, type == napi_string, "key not string type");
NAPI_CALL(env, napi_typeof(env, args[1], &type));
NAPI_ASSERT(env, type == napi_function, "observer not function type");
PreferencesProxy *obj = nullptr;
NAPI_CALL(env, napi_unwrap(env, _this, reinterpret_cast<void **>(&obj)));
obj->value_->UnRegisterObserver(obj->observer_);
obj->observer_.reset();
obj->observer_ = nullptr;
LOG_DEBUG("UnRegisterObserver end");
return nullptr;
}
PreferencesObserverImpl::PreferencesObserverImpl(napi_env env, napi_value callback) : observerRef(nullptr)
{
this->env_ = env;
napi_create_reference(env_, callback, 1, &observerRef);
}
PreferencesObserverImpl::~PreferencesObserverImpl()
{
napi_delete_reference(env_, observerRef);
}
void PreferencesObserverImpl::OnChange(Preferences &preferences, const std::string &key)
{
LOG_DEBUG("OnChange key:%{public}s", key.c_str());
napi_value callback = nullptr;
napi_value args[1] = {0};
napi_create_string_utf8(env_, key.c_str(), key.size(), &args[0]);
napi_get_reference_value(env_, observerRef, &callback);
napi_value global = nullptr;
napi_get_global(env_, &global);
napi_call_function(env_, global, callback, 1, args, nullptr);
LOG_DEBUG("OnChange key end");
}
} // namespace PreferencesJsKit
} // namespace OHOS

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_JSKIT_NAPI_PREFERENCE_H
#define PREFERENCES_JSKIT_NAPI_PREFERENCE_H
#include <assert.h>
#include "napi/native_common.h"
#include "napi/native_api.h"
#include "napi/native_node_api.h"
#include "preferences.h"
#include "preferences_helper.h"
namespace OHOS {
namespace PreferencesJsKit {
class PreferencesProxy {
public:
static void Init(napi_env env, napi_value exports);
static napi_value New(napi_env env, napi_callback_info info);
static napi_status NewInstance(napi_env env, napi_value arg, napi_value *instance);
static void Destructor(napi_env env, void *nativeObject, void *finalize_hint);
private:
explicit PreferencesProxy(std::shared_ptr<OHOS::NativePreferences::Preferences> value);
~PreferencesProxy();
static napi_value GetValueSync(napi_env env, napi_callback_info info);
static napi_value GetValue(napi_env env, napi_callback_info info);
static napi_value SetValueSync(napi_env env, napi_callback_info info);
static napi_value SetValue(napi_env env, napi_callback_info info);
static napi_value HasKeySync(napi_env env, napi_callback_info info);
static napi_value HasKey(napi_env env, napi_callback_info info);
static napi_value DeleteSync(napi_env env, napi_callback_info info);
static napi_value Delete(napi_env env, napi_callback_info info);
static napi_value FlushSync(napi_env env, napi_callback_info info);
static napi_value Flush(napi_env env, napi_callback_info info);
static napi_value ClearSync(napi_env env, napi_callback_info info);
static napi_value Clear(napi_env env, napi_callback_info info);
static napi_value RegisterObserver(napi_env env, napi_callback_info info);
static napi_value UnRegisterObserver(napi_env env, napi_callback_info info);
static napi_ref constructor;
std::shared_ptr<OHOS::NativePreferences::Preferences> value_;
napi_env env_;
napi_ref wrapper_;
std::shared_ptr<OHOS::NativePreferences::PreferencesObserver> observer_;
};
class PreferencesObserverImpl : public OHOS::NativePreferences::PreferencesObserver {
public:
PreferencesObserverImpl(napi_env env, napi_value callback);
virtual ~PreferencesObserverImpl();
void OnChange(OHOS::NativePreferences::Preferences &preferences, const std::string &key) override;
private:
napi_env env_;
napi_ref observerRef;
};
} // namespace PreferencesJsKit
} // namespace OHOS
#endif // PREFERENCES_JSKIT_NAPI_PREFERENCE_H

View File

@ -0,0 +1,202 @@
/*
* Copyright (c) 2021 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_preference_helper.h"
#include "securec.h"
#include "napi_preference.h"
#include "common.h"
#include "preferences_errno.h"
#include "napi_async_proxy.h"
using namespace OHOS::NativePreferences;
namespace OHOS {
namespace PreferencesJsKit {
struct HelperAysncContext : NapiAsyncProxy<HelperAysncContext>::AysncContext {
std::string path;
};
napi_value GetStorageSync(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1] = { 0 };
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
LOG_DEBUG("getPreferences %{public}zu", argc);
napi_value instance = nullptr;
NAPI_CALL(env, PreferencesProxy::NewInstance(env, args[0], &instance));
LOG_DEBUG("getPreferences end");
return instance;
}
void ParseString(const napi_env& env, const napi_value& value, HelperAysncContext* asyncContext)
{
if (asyncContext == nullptr) {
LOG_WARN("error input");
return;
}
char* path = new char[PATH_MAX];
memset_s(path, PATH_MAX, 0, PATH_MAX);
size_t pathLen = 0;
napi_get_value_string_utf8(env, value, path, PATH_MAX, &pathLen);
asyncContext->path = path;
delete[] path;
}
napi_value GetStorage(napi_env env, napi_callback_info info)
{
NapiAsyncProxy<HelperAysncContext> proxy;
proxy.Init(env, info);
std::vector<NapiAsyncProxy<HelperAysncContext>::InputParser> parsers;
parsers.push_back(ParseString);
proxy.ParseInputs(parsers);
return proxy.DoAsyncWork(
"GetStorage",
[](HelperAysncContext* asyncContext) {
int errCode = OK;
OHOS::NativePreferences::PreferencesHelper::GetPreferences(asyncContext->path, errCode);
LOG_DEBUG("GetPreferences return %{public}d", errCode);
return errCode;
},
[](HelperAysncContext* asyncContext, napi_value& output) {
napi_value path = nullptr;
napi_create_string_utf8(asyncContext->env, asyncContext->path.c_str(), NAPI_AUTO_LENGTH, &path);
auto ret = PreferencesProxy::NewInstance(asyncContext->env, path, &output);
return (ret == napi_ok) ? OK : ERR;
});
}
napi_status GetInputPath(napi_env env, napi_callback_info info, std::string &pathString)
{
size_t argc = 1;
napi_value args[1] = { 0 };
napi_status ret = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
if (ret != napi_ok) {
return ret;
}
napi_valuetype valueType;
ret = napi_typeof(env, args[0], &valueType);
if (ret != napi_ok || valueType != napi_string) {
return napi_invalid_arg;
}
char *path = new char[PATH_MAX];
memset_s(path, PATH_MAX, 0, PATH_MAX);
size_t pathLen = 0;
ret = napi_get_value_string_utf8(env, args[0], path, PATH_MAX, &pathLen);
pathString = path;
delete[] path;
return ret;
}
napi_value DeleteStorageSync(napi_env env, napi_callback_info info)
{
std::string path;
napi_status ret = GetInputPath(env, info, path);
if (ret != napi_ok) {
napi_throw_error(env, nullptr, "Input path error");
return nullptr;
}
LOG_DEBUG("deleteStorage %{public}s", path.c_str());
int errCode = PreferencesHelper::DeletePreferences(path);
if (errCode != E_OK) {
LOG_ERROR("deleteStorage failed %{public}d", errCode);
napi_throw_error(env, GetErrStr(errCode), "deleteStorage failed");
}
LOG_DEBUG("deleteStorage end");
return nullptr;
}
napi_value DeleteStorage(napi_env env, napi_callback_info info)
{
NapiAsyncProxy<HelperAysncContext> proxy;
proxy.Init(env, info);
std::vector<NapiAsyncProxy<HelperAysncContext>::InputParser> parsers;
parsers.push_back(ParseString);
proxy.ParseInputs(parsers);
return proxy.DoAsyncWork(
"DeleteStorage",
[](HelperAysncContext* asyncContext) {
int errCode = PreferencesHelper::DeletePreferences(asyncContext->path);
LOG_DEBUG("DeletePreferences return %{public}d", errCode);
return errCode;
},
[](HelperAysncContext* asyncContext, napi_value& output) {
napi_get_undefined(asyncContext->env, &output);
return OK;
});
}
napi_value RemoveStorageFromCacheSync(napi_env env, napi_callback_info info)
{
std::string path;
napi_status ret = GetInputPath(env, info, path);
if (ret != napi_ok) {
napi_throw_error(env, nullptr, "Input path error");
return nullptr;
}
LOG_DEBUG("removeStorageFromCache %{public}s", path.c_str());
int errCode = PreferencesHelper::RemovePreferencesFromCache(path);
if (errCode != E_OK) {
LOG_ERROR("removeStorageFromCache failed %{public}d", errCode);
napi_throw_error(env, GetErrStr(errCode), "removeStorageFromCache failed");
}
LOG_DEBUG("removeStorageFromCache end");
return nullptr;
}
napi_value RemoveStorageFromCache(napi_env env, napi_callback_info info)
{
NapiAsyncProxy<HelperAysncContext> proxy;
proxy.Init(env, info);
std::vector<NapiAsyncProxy<HelperAysncContext>::InputParser> parsers;
parsers.push_back(ParseString);
proxy.ParseInputs(parsers);
return proxy.DoAsyncWork(
"RemoveStorageFromCache",
[](HelperAysncContext* asyncContext) {
int errCode = PreferencesHelper::RemovePreferencesFromCache(asyncContext->path);
LOG_DEBUG("RemovePreferencesFromCache return %{public}d", errCode);
return errCode;
},
[](HelperAysncContext* asyncContext, napi_value& output) {
napi_get_undefined(asyncContext->env, &output);
return OK;
});
}
napi_value InitPreferenceHelper(napi_env env, napi_value exports)
{
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("getStorage", GetStorage),
DECLARE_NAPI_FUNCTION("getStorageSync", GetStorageSync),
DECLARE_NAPI_FUNCTION("deleteStorage", DeleteStorage),
DECLARE_NAPI_FUNCTION("deleteStorageSync", DeleteStorageSync),
DECLARE_NAPI_FUNCTION("removeStorageFromCache", RemoveStorageFromCache),
DECLARE_NAPI_FUNCTION("removeStorageFromCacheSync", RemoveStorageFromCacheSync),
};
NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(*properties), properties));
return exports;
}
} // namespace PreferencesJsKit
} // namespace OHOS

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_JSKIT_NAPI_PREFERENCE_HELPER_H
#define PREFERENCES_JSKIT_NAPI_PREFERENCE_HELPER_H
#include "napi/native_common.h"
#include "napi/native_api.h"
#include "napi/native_node_api.h"
namespace OHOS {
namespace PreferencesJsKit {
napi_value InitPreferenceHelper(napi_env env, napi_value exports);
}
} // namespace OHOS
#endif // PREFERENCES_JSKIT_NAPI_PREFERENCE_HELPER_H

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef RDB_JSKIT_COMMON_H
#define RDB_JSKIT_COMMON_H
#include <string>
#include <vector>
#include "hilog/log.h"
#include "rdb_errno.h"
namespace OHOS {
namespace RdbJsKit {
static const OHOS::HiviewDFX::HiLogLabel PREFIX_LABEL = { LOG_CORE, 0xD001650, "RdbJsKit" };
#define LOG_DEBUG(...) ((void)OHOS::HiviewDFX::HiLog::Debug(PREFIX_LABEL, __VA_ARGS__))
#define LOG_INFO(...) ((void)OHOS::HiviewDFX::HiLog::Info(PREFIX_LABEL, __VA_ARGS__))
#define LOG_WARN(...) ((void)OHOS::HiviewDFX::HiLog::Warn(PREFIX_LABEL, __VA_ARGS__))
#define LOG_ERROR(...) ((void)OHOS::HiviewDFX::HiLog::Error(PREFIX_LABEL, __VA_ARGS__))
#define LOG_FATAL(...) ((void)OHOS::HiviewDFX::HiLog::Fatal(PREFIX_LABEL, __VA_ARGS__))
static const std::vector<std::string> ERR_INFO {
"E_ERROR",
"E_CANNT_UPDATE_READONLY",
"E_REMOVE_FILE",
"E_EMPTY_FILE_NAME",
"E_EMPTY_TABLE_NAME",
"E_EMPTY_VALUES_BUCKET",
"E_INVALID_STATEMENT",
"E_INVALID_COLUMN_INDEX",
"E_INVALID_COLUMN_TYPE",
"E_INVALID_COLUMN_NAME",
"E_QUERY_IN_EXECUTE",
"E_TRANSACTION_IN_EXECUTE",
"E_EXECUTE_IN_STEP_QUERY",
"E_EXECUTE_WRITE_IN_READ_CONNECTION",
"E_BEGIN_TRANSACTION_IN_READ_CONNECTION",
"E_NO_TRANSACTION_IN_SESSION",
"E_MORE_STEP_QUERY_IN_ONE_SESSION",
"E_NO_ROW_IN_QUERY",
"E_INVLAID_BIND_ARGS_COUNT",
"E_INVLAID_ONJECT_TYPE",
"E_INVALID_CONFLICT_FLAG",
"E_HAVING_CLAUSE_NOT_IN_GROUP_BY",
"E_NOT_SUPPORTED_BY_STEP_RESULT_SET",
"E_STEP_RESULT_SET_CROSS_THREADS",
"E_STEP_RESULT_QUERY_NOT_EXECUTED",
"E_STEP_RESULT_IS_AFTER_LASET",
"E_STEP_RESULT_QUERY_EXCEEDED",
"E_STATMENT_NOT_PREPARED",
"E_EXECUTE_RESULT_INCORRECT",
"E_STEP_RESULT_CLOSED",
"E_RELATIVE_PATH",
"E_EMPTY_NEW_ENCRYPT_KEY",
"E_CHANGE_UNENCRYPTED_TO_ENCRYPTED",
"E_CHANGE_ENCRYPT_KEY_IN_BUSY",
"E_STEP_STATEMENT_NOT_INIT",
"E_NOT_SUPPROTED_ATTACH_IN_WAL_MODE"
};
static inline const char *GetErrStr(int err)
{
if (err == OHOS::NativeRdb::E_OK) {
return nullptr;
}
int index = err - OHOS::NativeRdb::E_BASE - 1;
if (index >= ERR_INFO.size() || index < 0) {
return "Unkown error";
}
return ERR_INFO.at(index).c_str();
}
} // namespace RdbJsKit
} // namespace OHOS
#endif

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2021 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 <unistd.h>
#include "napi/native_api.h"
#include "napi/native_node_api.h"
EXTERN_C_START
/*
* function for module exports
*/
static napi_value Init(napi_env env, napi_value exports)
{
return exports;
}
EXTERN_C_END
/*
* Module define
*/
static napi_module _module = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "data.rdb",
.nm_priv = ((void *)0),
.reserved = { 0 }
};
/*
* Module register function
*/
extern "C" __attribute__((constructor)) void RegisterModule(void)
{
napi_module_register(&_module);
}

View File

@ -0,0 +1,53 @@
# Copyright (c) 2021 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("//build/ohos.gni")
config("native_preferences_config") {
visibility = [ ":*" ]
include_dirs = [
"include",
"//foundation/distributeddatamgr/appdatamgr/frameworks/innerkitsimpl/native_preferences/include",
"//utils/native/base/include",
]
}
config("native_preferences_public_config") {
visibility = [ "//foundation/distributeddatamgr/appdatamgr:*" ]
include_dirs = [ "include" ]
}
ohos_shared_library("native_preferences") {
sources = [
"../../../frameworks/innerkitsimpl/native_preferences/src/preferences_helper.cpp",
"../../../frameworks/innerkitsimpl/native_preferences/src/preferences_impl.cpp",
"../../../frameworks/innerkitsimpl/native_preferences/src/preferences_observer.cpp",
"../../../frameworks/innerkitsimpl/native_preferences/src/preferences_value.cpp",
"../../../frameworks/innerkitsimpl/native_preferences/src/preferences_xml_utils.cpp",
"../../../frameworks/innerkitsimpl/native_preferences/src/task_pool.cpp",
"../../../frameworks/innerkitsimpl/native_preferences/src/task_queue.cpp",
]
configs = [ ":native_preferences_config" ]
deps = [
"//utils/native/base:utils",
"//third_party/libxml2:libxml2"
]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
public_configs = [ ":native_preferences_public_config" ]
subsystem_name = "distributeddatamgr"
part_name = "native_appdatamgr"
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_H
#define PREFERENCES_H
#include <string>
#include <vector>
#include "preferences_observer.h"
namespace OHOS {
namespace NativePreferences {
class Preferences {
public:
virtual ~Preferences(){};
static const unsigned int MAX_KEY_LENGTH = 80;
static const unsigned int MAX_VALUE_LENGTH = 8 * 1024;
virtual int GetInt(const std::string &key, int defValue) = 0;
virtual std::string GetString(const std::string &key, const std::string &defValue) = 0;
virtual bool GetBool(const std::string &key, bool defValue) = 0;
virtual float GetFloat(const std::string &key, float defValue) = 0;
virtual int64_t GetLong(const std::string &key, int64_t defValue) = 0;
virtual bool HasKey(const std::string &key) = 0;
virtual int PutInt(const std::string &key, int value) = 0;
virtual int PutString(const std::string &key, const std::string &value) = 0;
virtual int PutBool(const std::string &key, bool value) = 0;
virtual int PutLong(const std::string &key, int64_t value) = 0;
virtual int PutFloat(const std::string &key, float value) = 0;
virtual int Delete(const std::string &key) = 0;
virtual int Clear() = 0;
virtual void Flush() = 0;
virtual int FlushSync() = 0;
virtual void RegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver) = 0;
virtual void UnRegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver) = 0;
};
} // End of namespace NativePreferences
} // End of namespace OHOS
#endif // End of #ifndef PREFERENCES_H

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_ERRNO_H
#define PREFERENCES_ERRNO_H
#include <errno.h>
namespace OHOS {
namespace NativePreferences {
constexpr int E_OK = 0;
constexpr int E_BASE = 1000; // different from the other errno.
constexpr int E_ERROR = (E_BASE + 1);
constexpr int E_STALE = (E_BASE + 2); // Resource has been stopped, killed or destroyed.
constexpr int E_INVALID_ARGS = (E_BASE + 3); // the input args is invalid.
constexpr int E_OUT_OF_MEMORY = (E_BASE + 4); // out of memory
constexpr int E_NOT_PERMIT = (E_BASE + 5); // operation is not permitted
constexpr int E_KEY_EMPTY = (E_BASE + 6);
constexpr int E_KEY_EXCEED_MAX_LENGTH = (E_BASE + 7);
constexpr int E_PTR_EXIST_ANOTHER_HOLDER = (E_BASE + 8);
constexpr int E_DELETE_FILE_FAIL = (E_BASE + 9);
constexpr int E_EMPTY_FILE_PATH = (E_BASE + 10);
constexpr int E_RELATIVE_PATH = (E_BASE + 11);
constexpr int E_EMPTY_FILE_NAME = (E_BASE + 12);
constexpr int E_INVALID_FILE_PATH = (E_BASE + 13);
constexpr int E_PATH_EXCEED_MAX_LENGTH = (E_BASE + 14);
} // namespace NativePreferences
} // namespace OHOS
#endif // PREFERENCES_ERRNO_H

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_HELPER_H
#define PREFERENCES_HELPER_H
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include "preferences.h"
namespace OHOS {
namespace NativePreferences {
class PreferencesHelper {
public:
static std::shared_ptr<Preferences> GetPreferences(const std::string &path, int &errCode);
static int DeletePreferences(const std::string &path);
static int RemovePreferencesFromCache(const std::string &path);
private:
static std::map<std::string, std::shared_ptr<Preferences>> prefsCache_;
static std::mutex prefsCacheMutex_;
static std::string GetRealPath(const std::string &path, int &errorCode);
};
} // End of namespace NativePreferences
} // End of namespace OHOS
#endif // End of #ifndef PREFERENCES_HELPER_H

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef PREFERENCES_OBSERVER_H
#define PREFERENCES_OBSERVER_H
#include <string>
namespace OHOS {
namespace NativePreferences {
class Preferences;
class PreferencesObserver {
public:
virtual ~PreferencesObserver();
virtual void OnChange(Preferences &preferences, const std::string &key) = 0;
};
} // End of namespace NativePreferences
} // End of namespace OHOS
#endif // End of #ifndef PREFERENCES_OBSERVER_H

View File

@ -0,0 +1,62 @@
# Copyright (c) 2021 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("//build/ohos.gni")
config("native_rdb_config") {
visibility = [ ":*" ]
include_dirs = [
"include",
"../../../frameworks/innerkitsimpl/native_rdb/src",
]
defines = [ "SQLITE_HAS_CODEC" ]
}
config("native_rdb_public_config") {
visibility = [ "//foundation/distributeddatamgr/appdatamgr:*" ]
include_dirs = [ "include" ]
defines = [ "SQLITE_HAS_CODEC" ]
}
ohos_shared_library("native_rdb") {
part_name = "native_appdatamgr"
sources = [
"../../../frameworks/innerkitsimpl/native_rdb/src/rdb_helper.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/rdb_store_config.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/rdb_store_impl.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/sqlite_config.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/sqlite_connection.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/sqlite_connection_pool.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/sqlite_global_config.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/sqlite_sql_builder.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/sqlite_statement.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/sqlite_utils.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/step_result_set.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/store_session.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/value_object.cpp",
"../../../frameworks/innerkitsimpl/native_rdb/src/values_bucket.cpp",
]
configs = [ ":native_rdb_config" ]
deps = [ "//third_party/sqlite:sqlite" ]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
public_configs = [ ":native_rdb_public_config" ]
subsystem_name = "distributeddatamgr"
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_RDB_ERRNO_H
#define NATIVE_RDB_RDB_ERRNO_H
namespace OHOS {
namespace NativeRdb {
constexpr int E_OK = 0;
constexpr int E_BASE = 1000;
constexpr int E_ERROR = (E_BASE + 1);
constexpr int E_CANNT_UPDATE_READONLY = (E_BASE + 2);
constexpr int E_REMOVE_FILE = (E_BASE + 3);
constexpr int E_EMPTY_FILE_NAME = (E_BASE + 4);
constexpr int E_EMPTY_TABLE_NAME = (E_BASE + 5);
constexpr int E_EMPTY_VALUES_BUCKET = (E_BASE + 6);
constexpr int E_INVALID_STATEMENT = (E_BASE + 7);
constexpr int E_INVALID_COLUMN_INDEX = (E_BASE + 8);
constexpr int E_INVALID_COLUMN_TYPE = (E_BASE + 9);
constexpr int E_INVALID_COLUMN_NAME = (E_BASE + 10);
constexpr int E_QUERY_IN_EXECUTE = (E_BASE + 11);
constexpr int E_TRANSACTION_IN_EXECUTE = (E_BASE + 12);
constexpr int E_EXECUTE_IN_STEP_QUERY = (E_BASE + 13);
constexpr int E_EXECUTE_WRITE_IN_READ_CONNECTION = (E_BASE + 14);
constexpr int E_BEGIN_TRANSACTION_IN_READ_CONNECTION = (E_BASE + 15);
constexpr int E_NO_TRANSACTION_IN_SESSION = (E_BASE + 16);
constexpr int E_MORE_STEP_QUERY_IN_ONE_SESSION = (E_BASE + 17);
constexpr int E_NO_ROW_IN_QUERY = (E_BASE + 18);
constexpr int E_INVLAID_BIND_ARGS_COUNT = (E_BASE + 19);
constexpr int E_INVLAID_ONJECT_TYPE = (E_BASE + 20);
constexpr int E_INVALID_CONFLICT_FLAG = (E_BASE + 21);
constexpr int E_HAVING_CLAUSE_NOT_IN_GROUP_BY = (E_BASE + 22);
constexpr int E_NOT_SUPPORTED_BY_STEP_RESULT_SET = (E_BASE + 23);
constexpr int E_STEP_RESULT_SET_CROSS_THREADS = (E_BASE + 24);
constexpr int E_STEP_RESULT_QUERY_NOT_EXECUTED = (E_BASE + 25);
constexpr int E_STEP_RESULT_IS_AFTER_LASET = (E_BASE + 26);
constexpr int E_STEP_RESULT_QUERY_EXCEEDED = (E_BASE + 27);
constexpr int E_STATMENT_NOT_PREPARED = (E_BASE + 28);
constexpr int E_EXECUTE_RESULT_INCORRECT = (E_BASE + 29);
constexpr int E_STEP_RESULT_CLOSED = (E_BASE + 30);
constexpr int E_RELATIVE_PATH = (E_BASE + 31);
constexpr int E_EMPTY_NEW_ENCRYPT_KEY = (E_BASE + 32);
constexpr int E_CHANGE_UNENCRYPTED_TO_ENCRYPTED = (E_BASE + 33);
constexpr int E_CHANGE_ENCRYPT_KEY_IN_BUSY = (E_BASE + 34);
constexpr int E_STEP_STATEMENT_NOT_INIT = (E_BASE + 35);
constexpr int E_NOT_SUPPROTED_ATTACH_IN_WAL_MODE = (E_BASE + 36);
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_RDB_HELPER_H
#define NATIVE_RDB_RDB_HELPER_H
#include <memory>
#include <string>
#include "rdb_open_callback.h"
#include "rdb_store.h"
#include "rdb_store_config.h"
namespace OHOS {
namespace NativeRdb {
class RdbHelper final {
public:
static std::shared_ptr<RdbStore> GetRdbStore(
const RdbStoreConfig &config, int version, RdbOpenCallback &openCallback, int &errCode);
static int DeleteRdbStore(const std::string &path);
private:
static int ProcessOpenCallback(
RdbStore &rdbStore, const RdbStoreConfig &config, int version, RdbOpenCallback &openCallback);
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_RDB_OPEN_CALLBACK_H
#define NATIVE_RDB_RDB_OPEN_CALLBACK_H
#include "rdb_store.h"
namespace OHOS {
namespace NativeRdb {
class RdbOpenCallback {
public:
/**
* Called when the database associate whit this RdbStore is created with the first time.
* This is where the creation of tables and insert the initial data of tables should happen.
*
* param store The RdbStore object.
*/
virtual int OnCreate(RdbStore &rdbStore) = 0;
/**
* Called when the database associate whit this RdbStore needs to be upgrade.
*
* param store The RdbStore object.
* param oldVersion The old database version.
* param newVersion The new database version.
*/
virtual int OnUpgrade(RdbStore &rdbStore, int currentVersion, int targetVersion) = 0;
/**
* Called when the database associate whit this RdbStore needs to be downgrade.
*
* param store The RdbStore object.
* param oldVersion The old database version.
* param newVersion The new database version.
*/
virtual int OnDowngrade(RdbStore &rdbStore, int currentVersion, int targetVersion)
{
return 0;
}
/**
* Called when the RdbStore has been opened.
*
* param store The RdbStore object.
*/
virtual int OnOpen(RdbStore &rdbStore)
{
return 0;
}
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_RDB_STORE_H
#define NATIVE_RDB_RDB_STORE_H
#include <memory>
#include <string>
#include <vector>
#include "result_set.h"
#include "value_object.h"
#include "values_bucket.h"
namespace OHOS {
namespace NativeRdb {
enum class ConflictResolution {
ON_CONFLICT_NONE = 0,
ON_CONFLICT_ROLLBACK,
ON_CONFLICT_ABORT,
ON_CONFLICT_FAIL,
ON_CONFLICT_IGNORE,
ON_CONFLICT_REPLACE,
};
class RdbStore {
public:
virtual ~RdbStore(){};
virtual int Insert(int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues) = 0;
virtual int Replace(int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues) = 0;
virtual int InsertWithConflictResolution(int64_t &outRowId, const std::string &table,
const ValuesBucket &initialValues,
ConflictResolution conflictResolution = ConflictResolution::ON_CONFLICT_NONE) = 0;
virtual int Update(int &changedRows, const std::string &table, const ValuesBucket &values,
const std::string &whereClause = "",
const std::vector<std::string> &whereArgs = std::vector<std::string>()) = 0;
virtual int UpdateWithConflictResolution(int &changedRows, const std::string &table, const ValuesBucket &values,
const std::string &whereClause = "", const std::vector<std::string> &whereArgs = std::vector<std::string>(),
ConflictResolution conflictResolution = ConflictResolution::ON_CONFLICT_NONE) = 0;
virtual int Delete(int &deletedRows, const std::string &table, const std::string &whereClause = "",
const std::vector<std::string> &whereArgs = std::vector<std::string>()) = 0;
virtual std::unique_ptr<ResultSet> Query(int &errCode, bool distinct, const std::string &table,
const std::vector<std::string> &columns, const std::string &selection = "",
const std::vector<std::string> &selectionArgs = std::vector<std::string>(), const std::string &groupBy = "",
const std::string &having = "", const std::string &orderBy = "", const std::string &limit = "") = 0;
virtual std::unique_ptr<ResultSet> QuerySql(
const std::string &sql, const std::vector<std::string> &selectionArgs = std::vector<std::string>()) = 0;
virtual int ExecuteSql(
const std::string &sql, const std::vector<ValueObject> &bindArgs = std::vector<ValueObject>()) = 0;
virtual int ExecuteAndGetLong(int64_t &outValue, const std::string &sql,
const std::vector<ValueObject> &bindArgs = std::vector<ValueObject>()) = 0;
virtual int ExecuteAndGetString(std::string &outValue, const std::string &sql,
const std::vector<ValueObject> &bindArgs = std::vector<ValueObject>()) = 0;
virtual int GetVersion(int &version) = 0;
virtual int SetVersion(int version) = 0;
virtual int BeginTransaction() = 0;
virtual int MarkAsCommit() = 0;
virtual int EndTransaction() = 0;
virtual bool IsInTransaction() = 0;
virtual int ChangeEncryptKey(const std::vector<uint8_t> &newKey) = 0;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_RDB_STORE_CONFIG_H
#define NATIVE_RDB_RDB_STORE_CONFIG_H
#include <string>
#include <vector>
namespace OHOS {
namespace NativeRdb {
/* indicates the type of the storage */
enum class StorageMode {
MODE_MEMORY = 101,
MODE_DISK,
};
enum class JournalMode {
MODE_DELETE,
MODE_TRUNCATE,
MODE_PERSIST,
MODE_MEMORY,
MODE_WAL,
MODE_OFF,
};
class RdbStoreConfig {
public:
RdbStoreConfig(const std::string &path, StorageMode storageMode = StorageMode::MODE_DISK, bool readOnly = false,
const std::vector<uint8_t> &encryptKey = std::vector<uint8_t>());
~RdbStoreConfig();
/* set the journal mode, if not set, the default mode is WAL */
void SetJournalMode(JournalMode journalMode);
std::string GetPath() const;
StorageMode GetStorageMode() const;
std::string GetJournalMode() const;
bool IsReadOnly() const;
std::vector<uint8_t> GetEncryptKey() const;
void ClearEncryptKey();
private:
std::string path;
StorageMode storageMode;
bool readOnly;
std::vector<uint8_t> encryptKey;
std::string journalMode;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_RESULT_SET_H
#define NATIVE_RDB_RESULT_SET_H
#include <string>
namespace OHOS {
namespace NativeRdb {
/* Value returned by getColumnType(int) */
enum class ColumnType {
TYPE_NULL = 0,
TYPE_INTEGER,
TYPE_FLOAT,
TYPE_STRING,
TYPE_BLOB,
};
class ResultSet {
public:
virtual ~ResultSet(){};
/**
* Returns a string array holding the names of all of the columns in the
* result set.
*
* return the names of the columns contains in this query result.
*/
virtual int GetAllColumnNames(std::vector<std::string> &columnNames) = 0;
/**
* Return the total number of columns
*
* return the number of columns
*/
virtual int GetColumnCount(int &count) = 0;
/**
* Returns data type of the given column's value.
*
* param columnIndex the zero-based index of the target column.
* return column value type.
*/
virtual int GetColumnTypeForIndex(int columnIndex, ColumnType &columnType) const = 0;
/**
* Returns the zero-based index for the given column name.
*
* param columnName the name of the column.
* return the column index for the given column, or -1 if
* the column does not exist.
*/
virtual int GetColumnIndexForName(const std::string &columnName, int &columnIndex) = 0;
/**
* Returns the column name at the given column index.
*
* param columnIndex the zero-based index.
* return the column name for the given index.
*/
virtual int GetColumnNameForIndex(int columnIndex, std::string &columnName) = 0;
/**
* return the numbers of rows in the result set.
*/
virtual int GetRowCount(int &count) const = 0;
/**
* Returns the current position of the cursor in the result set.
* The value is zero-based. When the result set is first returned the cursor
* will be at position -1, which is before the first row.
* After the last row is returned another call to next() will leave the cursor past
* the last entry, at a position of count().
*
* return the current cursor position.
*/
virtual int GetRowIndex(int &position) const = 0;
/**
* Move the cursor a relative amount from current position. Positive offset move forward,
* negative offset move backward.
*
* param offset the offset to be applied from the current position.
* return whether the requested move succeeded.
*/
virtual int GoTo(int offset) = 0;
/**
* Move the cursor to an absolute position.
*
* param position the zero-based position to move to.
* return whether the requested move succeeded.
*/
virtual int GoToRow(int position) = 0;
/**
* Move the cursor to the first row.
*
* return whether the requested move succeeded.
*/
virtual int GoToFirstRow() = 0;
/**
* Move the cursor to the last row.
*
* return whether the requested move succeeded.
*/
virtual int GoToLastRow() = 0;
/**
* Move the cursor to the next row.
*
* return whether the requested move succeeded.
*/
virtual int GoToNextRow() = 0;
/**
* Move the cursor to the previous row.
*
* return whether the requested move succeeded.
*/
virtual int GoToPreviousRow() = 0;
/**
* Returns whether the cursor is pointing to the position after the last
* row.
*
* return whether the cursor is before the first row.
*/
virtual int IsEnded(bool &result) const = 0;
/**
* Returns whether the cursor is pointing to the position before the first
* row.
*
* return whether the cursor is before the first row.
*/
virtual int IsStarted(bool &result) const = 0;
/**
* Returns whether the cursor is pointing to the first row.
*
* return whether the cursor is pointing at the first entry.
*/
virtual int IsAtFirstRow(bool &result) const = 0;
/**
* Returns whether the cursor is pointing to the last row.
*
* return whether the cursor is pointing at the last entry.
*/
virtual int IsAtLastRow(bool &result) const = 0;
/**
* Returns the value of the requested column as a byte array.
*
* param columnIndex the zero-based index of the target column.
* return the value of the requested column as a byte array.
*/
virtual int GetBlob(int columnIndex, std::vector<uint8_t> &blob) const = 0;
/**
* Returns the value of the requested column as a String.
*
* param columnIndex the zero-based index of the target column.
* return the value of the requested column as a String.
*/
virtual int GetString(int columnIndex, std::string &value) const = 0;
/**
* Returns the value of the requested column as a int.
*
* param columnIndex the zero-based index of the target column.
* return the value of the requested column as a int.
*/
virtual int GetInt(int columnIndex, int &value) const = 0;
/**
* Returns the value of the requested column as a long.
*
* param columnIndex the zero-based index of the target column.
* return the value of the requested column as a long.
*/
virtual int GetLong(int columnIndex, int64_t &value) const = 0;
/**
* Returns the value of the requested column as a double.
*
* param columnIndex the zero-based index of the target column.
* return the value of the requested column as a double.
*/
virtual int GetDouble(int columnIndex, double &value) const = 0;
/**
* Whether the value of the requested column is null.
*
* param columnIndex the zero-based index of the target column.
* return whether the column value is null.
*/
virtual int IsColumnNull(int columnIndex, bool &isNull) const = 0;
/**
* Return true if the result set is closed.
*
* return true if the result set is closed.
*/
virtual bool IsClosed() const = 0;
/**
* Closes the result set, releasing all of its resources and making it
* completely invalid.
*/
virtual int Close() = 0;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_VALUE_OBJECT_H
#define NATIVE_RDB_VALUE_OBJECT_H
#include <string>
#include <variant>
#include <vector>
namespace OHOS {
namespace NativeRdb {
enum class ValueObjectType {
TYPE_NULL = 0,
TYPE_INT,
TYPE_DOUBLE,
TYPE_STRING,
TYPE_BLOB,
TYPE_BOOL,
};
class ValueObject {
public:
ValueObject();
~ValueObject();
explicit ValueObject(int val);
explicit ValueObject(int64_t val);
explicit ValueObject(double val);
explicit ValueObject(bool val);
explicit ValueObject(const std::string &val);
explicit ValueObject(const std::vector<uint8_t> &blob);
ValueObjectType GetType() const;
int GetInt(int &val) const;
int GetLong(int64_t &val) const;
int GetDouble(double &val) const;
int GetBool(bool &val) const;
int GetString(std::string &val) const;
int GetBlob(std::vector<uint8_t> &val) const;
private:
ValueObjectType type;
std::variant<int64_t, double, std::string, bool, std::vector<uint8_t>> value;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2021 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.
*/
#ifndef NATIVE_RDB_VALUES_BUCKET_H
#define NATIVE_RDB_VALUES_BUCKET_H
#include <map>
#include <set>
#include "value_object.h"
namespace OHOS {
namespace NativeRdb {
class ValuesBucket {
public:
ValuesBucket();
~ValuesBucket();
void PutString(const std::string &columnName, const std::string &value);
void PutInt(const std::string &columnName, int value);
void PutLong(const std::string &columnName, int64_t value);
void PutDouble(const std::string &columnName, double value);
void PutBool(const std::string &columnName, bool value);
void PutBlob(const std::string &columnName, const std::vector<uint8_t> &value);
void PutNull(const std::string &columnName);
void Delete(const std::string &columnName);
void Clear();
int Size() const;
bool IsEmpty() const;
bool HasColumn(const std::string &columnName) const;
bool GetObject(const std::string &columnName, ValueObject &value) const;
void GetAll(std::map<std::string, ValueObject> &valuesMap) const;
private:
std::map<std::string, ValueObject> valuesMap;
};
} // namespace NativeRdb
} // namespace OHOS
#endif

86
interfaces/jskits/BUILD.gn Executable file
View File

@ -0,0 +1,86 @@
# Copyright (c) 2021 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("//build/ohos.gni")
import("//build/ohos/ace/ace.gni")
js_declaration("appdatamgr_js") {
part_name = "appdatamgr_jskits"
sources = [
"./api/@ohos.data.rdb.d.ts",
"./api/@ohos.data.storage.d.ts",
"./api/@ohos.data"
]
}
ohos_copy("appdatamgr_declaration") {
sources = [
"./api"
]
outputs = [ target_out_dir + "/$target_name/" ]
module_source_dir = target_out_dir + "/$target_name"
module_install_name = ""
}
ohos_shared_library("storage") {
include_dirs = [
"//third_party/node/src",
"//utils/native/base/include",
"//foundation/distributeddatamgr/appdatamgr/frameworks/innerkitsimpl/native_preferences/include",
]
sources = [
"../../frameworks/jskitsimpl/native_preferences/napi_preference.cpp",
"../../frameworks/jskitsimpl/native_preferences/napi_preference_helper.cpp",
"../../frameworks/jskitsimpl/native_preferences/entry_point.cpp"
]
deps = [
"//foundation/ace/napi:ace_napi",
"//utils/native/base:utils"
]
external_deps = [
# "napi:napi_packages",
"native_appdatamgr:native_preferences",
"hiviewdfx_hilog_native:libhilog"
]
subsystem_name = "distributeddatamgr"
part_name = "appdatamgr_jskits"
relative_install_dir = "module/data"
}
ohos_shared_library("rdb") {
include_dirs = [
"//third_party/node/src"
]
sources = [
"../../frameworks/jskitsimpl/native_rdb/entry_point.cpp"
]
deps = [
"//foundation/ace/napi:ace_napi",
]
external_deps = [
# "napi:napi_packages",
"native_appdatamgr:native_rdb",
"hiviewdfx_hilog_native:libhilog"
]
subsystem_name = "distributeddatamgr"
part_name = "appdatamgr_jskits"
relative_install_dir = "module/data"
}

67
ohos.build Executable file
View File

@ -0,0 +1,67 @@
{
"subsystem": "distributeddatamgr",
"parts": {
"native_appdatamgr": {
"variants": [
"phone",
"wearable",
"ivi"
],
"module_list": [
"//foundation/distributeddatamgr/appdatamgr/interfaces/innerkits/native_preferences:native_preferences",
"//foundation/distributeddatamgr/appdatamgr/interfaces/innerkits/native_rdb:native_rdb"
],
"system_capabilities":[
"SystemCapability.Data.DATA_APPDATAMGR"
],
"inner_kits": [
{
"name": "//foundation/distributeddatamgr/appdatamgr/interfaces/innerkits/native_rdb:native_rdb",
"header": {
"header_files": [
"rdb_errno.h",
"rdb_helper.h",
"rdb_open_callback.h",
"rdb_store_config.h",
"rdb_store.h",
"result_set.h",
"value_object.h",
"values_bucket.h"
],
"header_base": "//foundation/distributeddatamgr/appdatamgr/interfaces/innerkits/native_rdb/include"
}
},
{
"name": "//foundation/distributeddatamgr/appdatamgr/interfaces/innerkits/native_preferences:native_preferences",
"header": {
"header_files": [
"preferences.h",
"preferences_observer.h",
"preferences_helper.h",
"preferences_errno.h"
],
"header_base": "//foundation/distributeddatamgr/appdatamgr/interfaces/innerkits/native_preferences/include"
}
}
],
"test_list": [
"//foundation/distributeddatamgr/appdatamgr/frameworks/innerkitsimpl/native_preferences/test:unittest",
"//foundation/distributeddatamgr/appdatamgr/frameworks/innerkitsimpl/native_rdb/test:unittest"
]
},
"appdatamgr_jskits": {
"variants": [
"phone",
"wearable",
"ivi"
],
"module_list": [
"//foundation/distributeddatamgr/appdatamgr/interfaces/jskits:storage"
],
"system_capabilities":[
"SystemCapability.Data.DATA_APPDATAMGR"
]
}
}
}