Merge branch 'prepare_for_master' of https://www.gitlink.org.cn/xuos/xiuos into 2023_open

This commit is contained in:
Liu_Weichao 2023-11-01 16:26:02 +08:00
commit 0aa73a14c2
32 changed files with 219173 additions and 5 deletions

View File

@ -272,7 +272,7 @@ CircularAreaAppType CircularAreaAppInit(uint32_t circular_area_length)
circular_area->p_tail = circular_area->data_buffer + circular_area_length;
circular_area->area_length = circular_area_length;
printf("CircularAreaAppInit done p_head %8p p_tail %8p length %lu\n",
printf("CircularAreaAppInit done p_head %8p p_tail %8p length %u\n",
circular_area->p_head, circular_area->p_tail, circular_area->area_length);
circular_area->CircularAreaAppOperations = &CircularAreaAppOperations;

View File

@ -163,6 +163,37 @@ int PrivTimerModify(timer_t timerid, int flags, const struct itimerspec *restric
/*********************fs**************************/
#ifdef FS_VFS
/************************Files Posix Transform***********************/
int PrivLseek(int fd, off_t offset, int whence)
{
return lseek(fd, offset, whence);
}
int PrivFsync(int fd)
{
return fsync(fd);
}
int PrivFstat(int fd, struct stat *buf)
{
return fstat(fd, buf);
}
int PrivStat(const char *path, struct stat *buf)
{
return stat(path, buf);
}
int PrivUnlink(const char *path)
{
return unlink(path);
}
char *PrivGetcwd(char *buf, size_t size)
{
return getcwd(buf, size);
}
/************************Driver Posix Transform***********************/
int PrivOpen(const char *path, int flags, ...)
{

View File

@ -430,6 +430,13 @@ int PrivTaskDelay(int32_t ms);
int PrivUserTaskSearch(void);
uint32_t PrivGetTickTime();
/*********************Files**************************/
int PrivLseek(int fd, off_t offset, int whence);
int PrivFsync(int fd);
int PrivFstat(int fd, struct stat *buf);
int PrivStat(const char *path, struct stat *buf);
int PrivUnlink(const char *path);
char *PrivGetcwd(char *buf, size_t size);
/*********************driver*************************/
int PrivOpen(const char *path, int flags, ...);

View File

@ -15,4 +15,5 @@ menu "app lib"
source "$APP_DIR/lib/embedded_database/Kconfig"
source "$APP_DIR/lib/lorawan/Kconfig"
source "$APP_DIR/lib/mqtt/Kconfig"
source "$APP_DIR/lib/SQLite/Kconfig"
endmenu

View File

@ -22,4 +22,8 @@ ifeq ($(CONFIG_TOOL_USING_MQTT),y)
SRC_DIR += mqtt
endif
ifeq ($(CONFIG_LIB_USING_SQLITE),y)
SRC_DIR += SQLite
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,21 @@
menu "lib using SQLite"
menuconfig LIB_USING_SQLITE
bool "Using SQLite lib"
default n
if LIB_USING_SQLITE
config LIB_SQLITE_EXAMPLE
bool "Enable SQLite example"
default y
config LIB_SQLITE_SQL_MAX_LEN
int "Set SQL statements max length"
default 1024
config LIB_SQLITE_DB_NAME_MAX_LEN
int "Set SQL database filename fullpath max length"
default 64
endif
endmenu

View File

@ -0,0 +1,10 @@
ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
SRC_FILES := sqlite3.c dbhelper.c
SRC_DIR := xizi_port
ifeq ($(CONFIG_LIB_SQLITE_EXAMPLE),y)
SRC_FILES += student_dao.c
endif
include $(KERNEL_ROOT)/compiler.mk
endif

View File

@ -0,0 +1,400 @@
# SQLite for RT-Thread
## 简介
SQLite 是一个小型,快速,独立的高可靠性全功能 SQL 数据库引擎。SQLite 是全世界部署最广泛的 SQL 数据库引擎。它内置在几乎所有的移动电话、大多数计算机以及部分嵌入式设备中,并被捆绑在人们每天使用的无数其他应用程序中。
## 文件说明
| 名称 | 说明 |
| ------------------------ | ---------------------------------------------------------------- |
| sqlite3.c | sqlite3源文件 |
| sqlite3.h | sqlite3头文件 |
| sqlite_config_rtthread.h | sqlite3在rt-thread上的配置文件 |
| rtthread_io_methods.c | rt-thread为sqlite提供的底层文件IO接口 |
| rtthread_mutex.c | rt-thread为sqlite提供的互斥量操作接口 |
| rtthread_vfs.c | rt-thread为sqlite提供的VFS(虚拟文件系统)接口 |
| xizi_io_methods.c | xizi为sqlite提供的底层文件IO接口 |
| xizi_mutex.c | xizi为sqlite提供的互斥量操作接口 |
| xizi_vfs.c | xizi为sqlite提供的VFS(虚拟文件系统)接口 |
| dbhelper.c | sqlite3操作接口封装简化应用 |
| dbhelper.h | dbhelper头文件向外部声明封装后的接口供用户调用 |
| student_dao.c | 简单的DAO层例程简单展示了对dbhelper的使用方法 |
| student_dao.h | 数据访问对象对外接口声明,线程可通过调用这些接口完成对该表的操作 |
## RT-Thread获取
在ENV中配置如下
```c
RT-Thread online packages --->
system packages --->
--- SQLite: a self-contained, high-reliability, embedded, full-featured, public-domain, SQL database engine.
(1024) SQL statements max length
[*] Enable example
```
配置项说明:
| 名称 | 说明 |
| ------------------------- | --------------------------------------------------- |
| SQL statements max length | SQL语句最大长度请根据实际业务需求设置。 |
| Enable example | 选择是否使能DAO层例程例程是模拟了学生成绩录入查询 |
## 依赖
- RT-Thread 3.X+
- DFS组件
## XiZi获取
在menuconfig中配置如下
```c
LIB_USING_SQLITE --->
[*] Enable SQLite example
(1024) Set SQL statements max length
(64) Set SQL database filename fullpath max length
```
配置项说明:
| 名称 | 说明 |
| -----------------------------| --------------------------------------------------- |
| Enable example | 选择是否使能DAO层例程例程是模拟了学生成绩录入查询 |
| SQL statements max length | SQL语句最大长度请根据实际业务需求设置。 |
| filename fullpath max length | SQL数据库文件名最大长度请根据实际业务需求设置。 |
## 依赖
- XiZi_IIoT
- shell线程栈不少于32KB
- TF卡驱动支持并挂载FATFS文件系统
## dbhelp接口说明
dbhelp是对sqlite3操作接口的封装目的是使用户更加简单地操作sqlite。
### 数据库文件完整路径
数据库文件的默认存放完整路径是"/rt.db"或"xiuos.db"用户可根据实际需求在dbhelper.h中修改。
```c
#define DB_NAME "/rt.db" 、"xiuos.db"
```
### 初始化
dbhelp初始化其中包含了sqlite的初始化及互斥量创建。用户无需再对数据库及锁初始化。
```c
int db_helper_init(void);
```
| 参数 | 说明 |
| --------- | ---------- |
| void | |
| 返回 | |
| RT_EOK | 初始化成功 |
| -RT_ERROR | 初始化失败 |
### 数据库创建
```c
int db_create_database(const char *sqlstr);
```
| 参数 | 说明 |
| ------ | --------------- |
| sqlstr | 创建表的SQL语句 |
| 返回 | |
| 0 | 成功 |
| 非0 | 失败 |
输入形参sqlstr应当是一条创建表的SQL语句
```c
const char *sql = "CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(32) NOT NULL,score INT NOT NULL);";
return db_create_database(sql);
```
### 可进行数据绑定的非查询操作
用于非查询的操作可通过回调进行数据绑定db_nonquery_operator中开启了事务功能支持操作失败后回滚。
```c
int db_nonquery_operator(const char *sqlstr, int (*bind)(sqlite3_stmt *, int index, void *arg), void *param);
```
| 参数 | 说明 |
| ------ | ------------------------------------------------------------ |
| sqlstr | 非查询类SQL语句如果有多个SQL语句要执行请用;将SQL语句分开 |
| bind | 数据绑定回调 |
| param | 在内部将赋值给bind的输入参数void *arg |
| 返回 | |
| 0 | 成功 |
| 非0 | 失败 |
注:该接口请勿用于查询类操作。
bind需要用户实现
| 参数 | 说明 |
| ---------------------- | -------------------------------------------------------------------- |
| stmt | sqlite3_stmt预备语句对象 |
| index | 如果有多条SQL语句要执行index表示第index条SQL语句注意index从1开始 |
| arg | 即db_nonquery_operator的四三个形参void *param |
| 返回 | |
| SQLITE_OK或SQLITE_DONE | 成功 |
| 其他 | 失败(如果用户提供的bind返回失败db_nonquery_operator将执行回滚操作) |
普通SQL语句在执行时是需要解析、编译、执行的而sqlite3_stmt结构是已经通过sqlite3_prepare函数对sql语句解析和编译了的而在SQL语句中在要绑定数据的位置放置?作为占位符即可通过数据绑定接口sqlite3_bind_*(此处*为通配符取值为intdoubletext等详情请见sqlite文档)。这种在批量操作时由于绕开了解释编译的过程直接在sqlite3_stmt的基础上对绑定值进行修改因而会使整体操作效率势大大提升。具体应用请见[student_dao.c](./student_dao.c)
### 带可变参数的非查询操作
```c
int db_nonquery_by_varpara(const char *sql, const char *fmt, ...);
```
| 参数 | 说明 |
| ---- | ----------------------------------------------------------------- |
| sql | 非查询类SQL语句 |
| fmt | 格式符配合后面的可变参数使用用法类似printf只支持%d,%f,%s,%x |
| ... | 可变形参 |
| 返回 | |
| 0 | 成功 |
| 非0 | 失败 |
注:该接口请勿用于查询类操作。
例:
```c
int student_del(int id)
{
return db_nonquery_by_varpara("delete from student where id=?;", "%d", id);
}
```
SQL语句"delete from student where id=?;"中,“?”为占位符id将会按照%d的格式被绑定到通过对前述SQL语句解释编译后的sqlite3_stmt中。
### 开启事务的非查询操作
db_nonquery_transaction开启了事务功能支持操作失败后回滚。
```c
int db_nonquery_transaction(int (*exec_sqls)(sqlite3 *db, void *arg), void *arg);
```
| 参数 | 说明 |
| --------- | ---------------------------------------------- |
| exec_sqls | SQL执行回调 |
| arg | 内部赋值给exec_sqls的void *arg形参作为输入参数 |
| 返回 | |
| 0 | 成功 |
| 非0 | 失败 |
exec_sqls
| 参数 | 说明 |
| ---------------------- | ---------------------------------------------------------------------------- |
| db | 数据库描述符 |
| arg | 来自于db_nonquery_transaction的形参void *arg |
| 返回 | |
| SQLITE_OK或SQLITE_DONE | 成功 |
| 其他 | 失败(如果用户提供的exec_sqls返回失败db_nonquery_transaction将执行回滚操作) |
注:该接口请勿用于查询类操作。
db_nonquery_transaction的自由度比较大内部开启事务后就开始执行exec_sqls用户可在exec_sqls通过调用SQLite的接口进行相关的数据库操作。执行完exec_sqls后提交事务。如果有失败情况会回滚。
### 带变参的查询操作
用户可通过sql语句及变参进行查询操作
```c
int db_query_by_varpara(const char *sql, int (*create)(sqlite3_stmt *stmt, void *arg), void *arg, const char *fmt, ...);
```
| 参数 | 说明 |
| ---------------------- | ----------------------------------------------------------------- |
| sql | SQL语句 |
| create | 创建用来接收查询结果的数据对象 |
| arg | 将赋值给create的void *arg作为输入参数 |
| fmt | 格式符配合后面的可变参数使用用法类似printf只支持%d,%f,%s,%x |
| ... | 变参 |
| 返回creat!=NULL | |
| 返回create的返回值 | |
| 返回create==NULL时 | |
| 0 | |
create回调
| 参数 | 说明 |
| --------------------------------- | ---------------------------------------------------- |
| stmt | sqlite3_stmt预备语句对象 |
| arg | 接收来由db_query_by_varpara的void *arg传递进来的形参 |
| 返回 | |
| 返回值将被db_query_by_varpara返回 | |
用户可通过调用在通过调用db_stmt_get_intdb_stmt_get_text等接口配合sqlite3_step获取查询结果回调接收不定数量的条目时请注意内存用量或在查询前先通过db_query_count_result确定条符合条件的条目数量。
### 获取符合条件的结果数量
调用此接口返回结果条目数量注意如的SQL语句应为SELECT COUNT为前缀的查询数量的语句。接口中只会获取第一行第一列。
```c
int db_query_count_result(const char *sql);
```
| 参数 | 说明 |
| ------ | ----------------------------------------------------------------- |
| sql | SQL语句仅限查询数量语句select count(*) from sqlite_master |
| 返回 | |
| 非负值 | 符合条件的条目的数量 |
| 负数 | 查询失败 |
例如,查询数据库中表的数量:
```c
nums = db_query_count_result("select count(*) from sqlite_master where type = 'table';");
```
### 在查询结果中获取blob型数据
在查询时获取blob类型数据blob类型在SQLite 中指二进制大对象,完全根据其输入值存储。
```c
int db_stmt_get_blob(sqlite3_stmt *stmt, int index, unsigned char *out)
```
| 参数 | 说明 |
| ------ | ---------------------------------------------- |
| stmt | sqlite3_stmt预备语句对象 |
| index | 数据索引 |
| out | 输出参数,获取到的数据将存入该指针指向的地址中 |
| 返回 | |
| 非负值 | 获取的数据长度 |
| 负数 | 查询失败 | |
### 在查询结果中获取text型数据
在查询时获取文本类型数据text类型值是一个文本字符串。
```c
int db_stmt_get_text(sqlite3_stmt *stmt, int index, char *out)
```
| 参数 | 说明 |
| ------ | ---------------------------------------------- |
| stmt | sqlite3_stmt预备语句对象 |
| index | 数据索引 |
| out | 输出参数,获取到的数据将存入该指针指向的地址中 |
| 返回 | |
| 非负值 | 获取的数据长度 |
| 负数 | 查询失败 |
### 在查询结果中获取int型数据
在查询时获取整型数据
```c
int db_stmt_get_int(sqlite3_stmt *stmt, int index);
```
| 参数 | 说明 |
| --------- | ------------------------ |
| stmt | sqlite3_stmt预备语句对象 |
| index | 数据索引 |
| 返回 | |
| int型变量 | 查询结果 |
### 在查询结果中获取double型数据
在查询时获取双精度数据
```c
double db_stmt_get_double(sqlite3_stmt *stmt, int index)
```
| 参数 | 说明 |
| ------------ | ------------------------ |
| stmt | sqlite3_stmt预备语句对象 |
| index | 数据索引 |
| 返回 | |
| double型变量 | 查询结果 |
### 通过表面查询表是否存在
可通过输入表名称来确定该表是否存在。
```c
int db_table_is_exist(const char *tbl_name)
```
| 参数 | 说明 |
| -------- | -------- |
| tbl_name | 表名称 |
| 返回 | |
| 正值 | 已存在 |
| 0 | 不存在 |
| 负值 | 查询错误 |
### 设置数据库文件名
该文件名应为绝对路径,请使用.db作为扩展名。在对单数据库的使用场景中可用来设置数据库名称。多线程多数据库请使用int db_connect(char *name)和int db_connect(char *name)。
```c
int db_set_name(char *name)
```
| 参数 | 说明 |
| ------ | ---------------------- |
| name | 文件名(完整绝对路径) |
| 返回 | |
| RT_EOK | 设置成功 |
| <0 | 设置失败 |
### 读取当前数据库文件名
```c
const char *db_get_name(void)
```
| 参数 | 说明 |
| ------ | -------- |
| 返回 | |
| 字符串 | 设置成功 |
| <0 | 设置失败 |
### 连接数据库
该文件名应为绝对路径,请使用.db作为扩展名该方法将会设置要打开的数据库文件名并加锁操作完毕后请调用 int db_disconnect(char *name) 解锁,以便以其他线程操作。适用于多线程操作多数据库场景。如果是多线程,单数据库场景请使用 int db_set_name(char *name) 来修改数据库名称或直接操作数据库(即使用默认数据库名称)。
```c
int db_connect(char *name)
```
| 参数 | 说明 |
| ------ | ---------------------- |
| name | 文件名(完整绝对路径) |
| 返回 | |
| RT_EOK | 设置成功 |
| <0 | 设置失败 |
### 断开数据库连接
断开数据库连接,数据库名称将恢复为默认,并释放互斥量。
```c
int db_connect(char *name)
```
| 参数 | 说明 |
| ------ | ---------------------- |
| name | 文件名(完整绝对路径) |
| 返回 | |
| RT_EOK | 设置成功 |
| <0 | 设置失败 |
## DAO层实例
这是一个学生成绩录入查询的DAO(Data Access Object)层示例可在menuconfig中配置使能。通过此例程可更加详细的了解dbhelper的使用方法。例程配置使能后可通过命令行实现对student表的操作具体命令如下
说明:以下命令中被[]包裹的为必填参数,<>包裹的为非必填参数
### stu add \<num\>
增加\<num\>个学生信息。学生名称和成绩为一定范围内的生成的随机值。如果仅输入```stu add```则默认插入一条学生信息。
### stu del <id>
删除主键为\<id\>的学生成绩信息,如果仅输入```stu del```则删除全部学生信息。例如:
```
stu del 1
```
删除主键为1的学生成绩信息。
### stu update [id] [name] [score]
将主键为[id]的学生的姓名及分数分别修改为[name]和[score]。例如:
```
stu update 1 lizhen9880 100
```
表示将主键为1的条目中学生姓名修改为lizhen9880分数修改为100。
### stu \<id\>
根据id查询学生成绩并打印id为该表自增主键具备唯一性。根据主键查询速度是非常快的。
仅输入 ```stu``` 会查询出所有学生名称成绩并打印,例:
```
stu 3
```
将查询出主键为3的学生成绩信息并打印。
### stu score [ls] [hs] \<-d|-a\>
查询并打印分数在[ls]到[hs]之间的学生成绩单。<br/>
[ls]: 最低分 <br/>
[hs]: 最高分 <br/>
\<-d|-a\>: -d 降序;-a 升序;默认升序
例如:
```
stu score 60 100 -d
```
按照```降序```打印出成绩及格学生的成绩单。
```
stu score 60 100
```
按照```升序```打印出成绩及格学生的成绩单。
## 注意事项
- SQLite资源占用RAM:250KB+,ROM:310KB+,所以需要有较充足的硬件资源。
- 根据应用场景创建合理的表结构,会提高操作效率。
- 根据应用场合理使用SQL语句如查询条件插入方式等。
- 如涉及到多表操作或联表查询最好使用PowerDesigner等工具合理设计表。
## 相关链接
Env工具获取[https://www.rt-thread.org/page/download.html](https://www.rt-thread.org/page/download.html)
Env工具使用[https://www.rt-thread.org/document/site/zh/5chapters/01-chapter_env_manual/#env](https://www.rt-thread.org/document/site/zh/5chapters/01-chapter_env_manual/#env)
SQLite官方文档[https://www.sqlite.org/docs.html](https://www.sqlite.org/docs.html)
## Q&F
联系人: RT-Thread官方 | [lizhen9880](https://github.com/lizhen9880)<br/>
邮箱:[package_team@rt-thread.com](package_team@rt-thread.com) | [lizhen9880@126.com](lizhen9880@126.com)

View File

@ -0,0 +1,12 @@
from building import *
cwd = GetCurrentDir()
src = ['sqlite3.c']
src += ['dbhelper.c']
if GetDepend('PKG_SQLITE_DAO_EXAMPLE'):
src += Glob('student_dao.c')
CPPPATH = [cwd]
group = DefineGroup('sqlite', src, depend = ['RT_USING_DFS', 'PKG_USING_SQLITE'], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,770 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-06 lizhen9880 first version
*/
/**
* @file dbhelper.c
* @brief support SQLite api function for applications in XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-25
*/
/*************************************************
File name: dbhelper.c
Description: support SQLite api function for applications in XiUOS
Others:
History:
1. Date: 2023-10-25
Author: AIIT XUOS Lab
Modification:
1add XiUOS function.
*************************************************/
#include <stdio.h>
#include <string.h>
#include <transform.h>
#ifdef ADD_XIZI_FEATURES
#include <sqlite_config_xiuos.h>
#endif
#ifdef ADD_RTTHREAD_FEATURES
#include <rtthread.h>
#endif
#include <ctype.h>
#include "dbhelper.h"
#define DBG_ENABLE
#define DBG_SECTION_NAME "app.dbhelper"
#define DBG_LEVEL DBG_INFO
#define DBG_COLOR
#ifdef ADD_RTTHREAD_FEATURES
#include <rtdbg.h>
#endif
#if PKG_SQLITE_DB_NAME_MAX_LEN < 8
#error "the database name length is too short"
#endif
#ifdef ADD_RTTHREAD_FEATURES
#define DEFAULT_DB_NAME "/rt.db"
#endif
#ifdef ADD_XIZI_FEATURES
#define DEFAULT_DB_NAME "xiuos.db"
#endif
#ifdef ADD_RTTHREAD_FEATURES
static rt_mutex_t db_mutex_lock = RT_NULL;
#endif
#ifdef ADD_XIZI_FEATURES
static pthread_mutex_t db_mutex_lock;
#endif
static char db_name[PKG_SQLITE_DB_NAME_MAX_LEN + 1] = DEFAULT_DB_NAME;
/**
* This function will initialize SQLite3 create a mutex as a lock.
*/
#ifdef ADD_RTTHREAD_FEATURES
int db_helper_init(void)
{
sqlite3_initialize();
if (db_mutex_lock == RT_NULL)
{
db_mutex_lock = rt_mutex_create("dbmtx", RT_IPC_FLAG_FIFO);
}
if (db_mutex_lock == RT_NULL)
{
LOG_E("rt_mutex_create dbmtx failed!\n");
return -RT_ERROR;
}
return RT_EOK;
}
INIT_APP_EXPORT(db_helper_init);
#endif
#ifdef ADD_XIZI_FEATURES
int db_helper_init(void)
{
int ret = 0;
sqlite3_initialize();
ret = PrivMutexCreate(&db_mutex_lock, 0);
if (ret < 0)
{
printf("mutex_create dbmtx failed!\n");
return -1;
}
return 0;
}
PRIV_SHELL_CMD_FUNCTION(db_helper_init, initialize SQLite3 and create a mutex, PRIV_SHELL_CMD_FUNC_ATTR);
#endif
/**
* This function will create a database.
*
* @param sqlstr should be a SQL CREATE TABLE statements.
* @return the result of sql execution.
*/
int db_create_database(const char *sqlstr)
{
return db_nonquery_operator(sqlstr, 0, 0);
}
static int db_bind_by_var(sqlite3_stmt *stmt, const char *fmt, va_list args)
{
int len, npara = 1;
int ret = SQLITE_OK;
if (fmt == NULL)
{
return ret;
}
for (; *fmt; ++fmt)
{
if (*fmt != '%')
{
continue;
}
++fmt;
/* get length */
len = 0;
while (isdigit(*fmt))
{
len = len * 10 + (*fmt - '0');
++fmt;
}
switch (*fmt)
{
case 'd':
ret = sqlite3_bind_int(stmt, npara, va_arg(args, int));
break;
case 'f':
ret = sqlite3_bind_double(stmt, npara, va_arg(args, double));
break;
case 's':
{
char *str = va_arg(args, char *);
ret = sqlite3_bind_text(stmt, npara, str, strlen(str), NULL);
}
break;
case 'x':
{
char *pdata;
pdata = va_arg(args, char *);
ret = sqlite3_bind_blob(stmt, npara, pdata, len, NULL);
}
break;
default:
ret = SQLITE_ERROR;
break;
}
++npara;
if (ret)
return ret;
}
return ret;
}
/**
* This function will be used for the SELECT operating.The additional arguments
* following format are formatted and inserted in the resulting string replacing
* their respective specifiers.
*
* @param sql the SQL statements.
* @param create the callback function supported by user.
* create@param stmt the SQL statement after preparing.
* create@param arg the input parameter from 'db_query_by_varpara' arg.
* create@return rule:SQLITE_OK:success,others:fail
* @param arg the parameter for the callback "create".
* @param fmt the args format.such as %s string,%d int.
* @param ... the additional arguments
* @return =SQLITE_OK:success, others:fail.
*/
int db_query_by_varpara(const char *sql, int (*create)(sqlite3_stmt *stmt, void *arg), void *arg, const char *fmt, ...)
{
sqlite3 *db = NULL;
sqlite3_stmt *stmt = NULL;
if (sql == NULL)
{
return SQLITE_ERROR;
}
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_take(db_mutex_lock, RT_WAITING_FOREVER);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexObtain(&db_mutex_lock);
#endif
int rc = sqlite3_open(db_name, &db);
if (rc != SQLITE_OK)
{
printf("open database failed,rc=%d", rc);
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return rc;
}
rc = sqlite3_prepare(db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK)
{
printf("database prepare fail,rc=%d", rc);
goto __db_exec_fail;
}
if (fmt)
{
va_list args;
va_start(args, fmt);
rc = db_bind_by_var(stmt, fmt, args);
va_end(args);
if (rc)
{
printf("database bind fail,rc=%d", rc);
goto __db_exec_fail;
}
}
if (create)
{
rc = (*create)(stmt, arg);
}
else
{
rc = (sqlite3_step(stmt), 0);
}
sqlite3_finalize(stmt);
goto __db_exec_ok;
__db_exec_fail:
printf("db operator failed,rc=%d", rc);
__db_exec_ok:
sqlite3_close(db);
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return rc;
}
/**
* This function will be used for the operating that is not SELECT.It support executing multiple
* SQL statements.
*
* @param sqlstr the SQL statements strings.if there are more than one
* statements in the sqlstr to execute,separate them by a semicolon(;).
* @param bind the callback function supported by user.bind data and call the sqlite3_step function.
* bind@param stmt the SQL statement after preparing.
* bind@param index the index of SQL statements strings.
* bind@param param the parameter from 'db_nonquery_operator' arg.
* bind@return SQLITE_OK or SQLITE_DONE:success,others:fail
* @param param the parameter for the callback "bind".
* @return =SQLITE_OK:success, others:fail.
*/
int db_nonquery_operator(const char *sqlstr, int (*bind)(sqlite3_stmt *stmt, int index, void *param), void *param)
{
sqlite3 *db = NULL;
sqlite3_stmt *stmt = NULL;
int index = 0, offset = 0, n = 0;
if (sqlstr == NULL)
{
return SQLITE_ERROR;
}
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_take(db_mutex_lock, RT_WAITING_FOREVER);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexObtain(&db_mutex_lock);
#endif
int rc = sqlite3_open(db_name, &db);
if (rc != SQLITE_OK)
{
printf("open database failed,rc=%d", rc);
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return rc;
}
rc = sqlite3_exec(db, "begin transaction", 0, 0, NULL);
if (rc != SQLITE_OK)
{
printf("begin transaction:ret=%d", rc);
goto __db_begin_fail;
}
char sql[DB_SQL_MAX_LEN];
while (sqlstr[index] != 0)
{
offset = 0;
do
{
if (offset >= DB_SQL_MAX_LEN)
{
printf("sql is too long,(%d)", offset);
rc = SQLITE_ERROR;
goto __db_exec_fail;
}
if ((sqlstr[index] != ';') && (sqlstr[index] != 0))
{
sql[offset++] = sqlstr[index++];
}
else
{
sql[offset] = '\0';
if (sqlstr[index] == ';')
{
index++;
}
n++;
break;
}
} while (1);
rc = sqlite3_prepare(db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK)
{
printf("prepare error,rc=%d", rc);
goto __db_exec_fail;
}
if (bind)
{
rc = (*bind)(stmt, n, param);
}
else
{
rc = sqlite3_step(stmt);
}
sqlite3_finalize(stmt);
if ((rc != SQLITE_OK) && (rc != SQLITE_DONE))
{
printf("bind failed");
goto __db_exec_fail;
}
}
rc = sqlite3_exec(db, "commit transaction", 0, 0, NULL);
if (rc)
{
printf("commit transaction:%d", rc);
goto __db_exec_fail;
}
goto __db_exec_ok;
__db_exec_fail:
if (sqlite3_exec(db, "rollback transaction", 0, 0, NULL))
{
printf("rollback transaction error");
}
__db_begin_fail:
printf("db operator failed,rc=%d", rc);
__db_exec_ok:
sqlite3_close(db);
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return rc;
}
/**
* This function will be used for the operating that is not SELECT.The additional
* arguments following format are formatted and inserted in the resulting string
* replacing their respective specifiers.
*
* @param sql the SQL statement.
* @param fmt the args format.such as %s string,%d int.
* @param ... the additional arguments
* @return =SQLITE_OK:success, others:fail.
*/
int db_nonquery_by_varpara(const char *sql, const char *fmt, ...)
{
sqlite3 *db = NULL;
sqlite3_stmt *stmt = NULL;
if (sql == NULL)
{
return SQLITE_ERROR;
}
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_take(db_mutex_lock, RT_WAITING_FOREVER);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexObtain(&db_mutex_lock);
#endif
int rc = sqlite3_open(db_name, &db);
if (rc != SQLITE_OK)
{
printf("open database failed,rc=%d\n", rc);
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return rc;
}
printf("sql:%s", sql);
rc = sqlite3_prepare(db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK)
{
printf("prepare error,rc=%d", rc);
goto __db_exec_fail;
}
if (fmt)
{
va_list args;
va_start(args, fmt);
rc = db_bind_by_var(stmt, fmt, args);
va_end(args);
if (rc)
{
goto __db_exec_fail;
}
}
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if ((rc != SQLITE_OK) && (rc != SQLITE_DONE))
{
printf("bind error,rc=%d", rc);
goto __db_exec_fail;
}
rc = SQLITE_OK;
goto __db_exec_ok;
__db_exec_fail:
printf("db operator failed,rc=%d", rc);
__db_exec_ok:
sqlite3_close(db);
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return rc;
}
/**
* This function will be used for the transaction that is not SELECT.
*
* @param exec_sqls the callback function of executing SQL statements.
* exec_sqls@param db the database connection handle
* exec_sqls@param arg the input parameter from 'db_nonquery_transaction' function parameter 'arg'.
* exec_sqls@return =SQLITE_OK or =SQLITE_DONE:success,others:fail
* @param arg the parameter for the callback "exec_sqls".
* @return =SQLITE_OK:success, others:fail.
*/
int db_nonquery_transaction(int (*exec_sqls)(sqlite3 *db, void *arg), void *arg)
{
sqlite3 *db = NULL;
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_take(db_mutex_lock, RT_WAITING_FOREVER);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexObtain(&db_mutex_lock);
#endif
int rc = sqlite3_open(db_name, &db);
if (rc != SQLITE_OK)
{
printf("open database failed,rc=%d", rc);
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return rc;
}
rc = sqlite3_exec(db, "begin transaction", 0, 0, NULL);
if (rc != SQLITE_OK)
{
printf("begin transaction:%d", rc);
goto __db_begin_fail;
}
if (exec_sqls)
{
rc = (*exec_sqls)(db, arg);
}
else
{
rc = SQLITE_ERROR;
}
if ((rc != SQLITE_OK) && (rc != SQLITE_DONE))
{
printf("prepare error,rc=%d", rc);
goto __db_exec_fail;
}
rc = sqlite3_exec(db, "commit transaction", 0, 0, NULL);
if (rc)
{
printf("commit transaction:%d", rc);
goto __db_exec_fail;
}
goto __db_exec_ok;
__db_exec_fail:
if (sqlite3_exec(db, "rollback transaction", 0, 0, NULL))
{
printf("rollback transaction:error");
}
__db_begin_fail:
printf("db operator failed,rc=%d", rc);
__db_exec_ok:
sqlite3_close(db);
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return rc;
}
static int db_get_count(sqlite3_stmt *stmt, void *arg)
{
int ret, *count = arg;
ret = sqlite3_step(stmt);
if (ret != SQLITE_ROW)
{
return SQLITE_EMPTY;
}
*count = db_stmt_get_int(stmt, 0);
return SQLITE_OK;
}
/**
* This function will return the number of records returned by a select query.
* This function only gets the 1st row of the 1st column.
*
* @param sql the SQL statement SELECT COUNT() FROM .
* @return >=0:the count ,<0: fail.
*/
int db_query_count_result(const char *sql)
{
int ret, count = 0;
ret = db_query_by_varpara(sql, db_get_count, &count, NULL);
if (ret == SQLITE_OK)
{
return count;
}
return -1;
}
/**
* This function will get the blob from the "index" colum.
*
* @param stmt the SQL statement returned by the function sqlite3_step().
* @param index the colum index.the first colum's index value is 0.
* @param out the output buffer.the result will put in this buffer.
* @return >=0:the result length ,<0: fail.
*/
int db_stmt_get_blob(sqlite3_stmt *stmt, int index, unsigned char *out)
{
const char *pdata = sqlite3_column_blob(stmt, index);
int len = sqlite3_column_bytes(stmt, index);
if (pdata)
{
memcpy(out, pdata, len);
return len;
}
return -1;
}
/**
* This function will get the text from the "index" colum.
*
* @param stmt the SQL statement returned by the function sqlite3_step().
* @param index the colum index.the first colum's index value is 0.
* @param out the output buffer.the result will put in this buffer.
* @return >=0:the result length ,<0: fail.
*/
int db_stmt_get_text(sqlite3_stmt *stmt, int index, char *out)
{
const unsigned char *pdata = sqlite3_column_text(stmt, index);
if (pdata)
{
int len = strlen((char *)pdata);
strncpy(out, (char *)pdata, len);
return len;
}
return -1;
}
/**
* This function will get a integer from the "index" colum.
*
* @param stmt the SQL statement returned by the function sqlite3_step().
* @param index the colum index.the first colum's index value is 0.
* @return the result.
*/
int db_stmt_get_int(sqlite3_stmt *stmt, int index)
{
return sqlite3_column_int(stmt, index);
}
/**
* This function will get a double precision value from the "index" colum.
*
* @param stmt the SQL statement returned by the function sqlite3_step().
* @param index the colum index.the first colum's index value is 0.
* @return the result.
*/
double db_stmt_get_double(sqlite3_stmt *stmt, int index)
{
return sqlite3_column_double(stmt, index);
}
/**
* This function will check a table exist or not by table name.
*
* @param tbl_name the table name.
* @return >0:existed; ==0:not existed; <0:ERROR
*/
int db_table_is_exist(const char *tbl_name)
{
char sqlstr[DB_SQL_MAX_LEN];
int cnt = 0;
if (tbl_name == NULL)
{
return -1;
}
snprintf(sqlstr, DB_SQL_MAX_LEN, "select count(*) from sqlite_master where type = 'table' and name = '%s';", tbl_name);
cnt = db_query_count_result(sqlstr);
if (cnt > 0)
{
return cnt;
}
return -1;
}
/**
* This function will connect DB
*
* @param name the DB filename.
* @return 0:success
* -1:the input name is too long
*/
int db_connect(char *name)
{
int32_t len = 0;
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_take(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexObtain(&db_mutex_lock);
#endif
len = strnlen(name, PKG_SQLITE_DB_NAME_MAX_LEN + 1);
if (len >= PKG_SQLITE_DB_NAME_MAX_LEN + 1)
{
printf("the database name '(%s)' lengh is too long(max:%d).", name, PKG_SQLITE_DB_NAME_MAX_LEN);
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return -1;
}
strncpy(db_name, name, len);
db_name[len] = '\0';
return 0;
}
/**
* This function will disconnect DB
*
* @param name the DB filename.
* @return 0:success
* -1:the input name is too long
*/
int db_disconnect(char *name)
{
int32_t len = 0;
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
strncpy(db_name, DEFAULT_DB_NAME, strlen(DEFAULT_DB_NAME));
db_name[len] = '\0';
return 0;
}
/**
* This function will connect DB
*
* @param name the DB filename.
* @return 0:success
* -1:the input name is too long
*/
int db_set_name(char *name)
{
int32_t len = 0;
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_take(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexObtain(&db_mutex_lock);
#endif
len = strnlen(name, PKG_SQLITE_DB_NAME_MAX_LEN + 1);
if (len >= PKG_SQLITE_DB_NAME_MAX_LEN + 1)
{
printf("the database name '(%s)' lengh is too long(max:%d).", name, PKG_SQLITE_DB_NAME_MAX_LEN);
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return -1;
}
strncpy(db_name, name, len);
db_name[len] = '\0';
#ifdef ADD_RTTHREAD_FEATURES
rt_mutex_release(db_mutex_lock);
#endif
#ifdef ADD_XIZI_FEATURES
PrivMutexAbandon(&db_mutex_lock);
#endif
return 0;
}
/**
* This function will get the current DB filename
*
* @return the current DB filename
*
*/
char *db_get_name(void)
{
static char name[PKG_SQLITE_DB_NAME_MAX_LEN + 1];
size_t len = strlen(db_name);
strncpy(name, db_name, len);
name[len] = '\0';
return name;
}

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-06 lizhen9880 first version
*/
#ifndef __DBHELPER_H__
#define __DBHELPER_H__
#include <sqlite3.h>
#ifdef ADD_RTTHREAD_FEATURES
#include <rtthread.h>
#endif
#define DB_SQL_MAX_LEN PKG_SQLITE_SQL_MAX_LEN
int db_helper_init(void);
int db_create_database(const char *sqlstr);
/**
* This function will be used for the operating that is not SELECT.It support executing multiple
* SQL statements.
*
* @param sqlstr the SQL statements strings.if there are more than one
* statements in the sqlstr to execute,separate them by a semicolon(;).
* @param bind the callback function supported by user.bind data and call the sqlite3_step function.
* @param param the parameter for the callback "bind".
* @return success or fail.
*/
int db_nonquery_operator(const char *sqlstr, int (*bind)(sqlite3_stmt *, int index, void *arg), void *param);
/**
* This function will be used for the operating that is not SELECT.The additional
* arguments following format are formatted and inserted in the resulting string
* replacing their respective specifiers.
*
* @param sql the SQL statement.
* @param fmt the args format.such as %s string,%d int.
* @param ... the additional arguments
* @return success or fail.
*/
int db_nonquery_by_varpara(const char *sql, const char *fmt, ...);
/**
* This function will be used for the transaction that is not SELECT.
*
* @param exec_sqls the callback function of executing SQL statements.
* @param arg the parameter for the callback "exec_sqls".
* @return success or fail.
*/
int db_nonquery_transaction(int (*exec_sqls)(sqlite3 *db, void *arg), void *arg);
/**
* This function will be used for the SELECT operating.The additional arguments
* following format are formatted and inserted in the resulting string replacing
* their respective specifiers.
*
* @param sql the SQL statements.
* @param create the callback function supported by user.
* @param arg the parameter for the callback "create".
* @param fmt the args format.such as %s string,%d int.
* @param ... the additional arguments
* @return success or fail.
*/
int db_query_by_varpara(const char *sql, int (*create)(sqlite3_stmt *stmt, void *arg), void *arg, const char *fmt, ...);
/**
* This function will return the number of records returned by a select query.
* This function only gets the 1st row of the 1st column.
*
* @param sql the SQL statement SELECT COUNT() FROM .
* @return the count or fail.
*/
int db_query_count_result(const char *sql);
/**
* This function will get the blob from the "index" colum.
*
* @param stmt the SQL statement returned by the function sqlite3_step().
* @param index the colum index.the first colum's index value is 0.
* @param out the output buffer.the result will put in this buffer.
* @return the result length or fail.
*/
int db_stmt_get_blob(sqlite3_stmt *stmt, int index, unsigned char *out);
/**
* This function will get the text from the "index" colum.
*
* @param stmt the SQL statement returned by the function sqlite3_step().
* @param index the colum index.the first colum's index value is 0.
* @param out the output buffer.the result will put in this buffer.
* @return the result length or fail.
*/
int db_stmt_get_text(sqlite3_stmt *stmt, int index, char *out);
/**
* This function will get a integer from the "index" colum.
*
* @param stmt the SQL statement returned by the function sqlite3_step().
* @param index the colum index.the first colum's index value is 0.
* @return the result.
*/
int db_stmt_get_int(sqlite3_stmt *stmt, int index);
/**
* This function will get a double precision value from the "index" colum.
*
* @param stmt the SQL statement returned by the function sqlite3_step().
* @param index the colum index.the first colum's index value is 0.
* @return the result.
*/
double db_stmt_get_double(sqlite3_stmt *stmt, int index);
/**
* This function will check a table exist or not by table name.
*
* @param tbl_name the table name.
* @return >0:existed; ==0:not existed; <0:ERROR
*/
int db_table_is_exist(const char *tbl_name);
/**
* This function will connect DB
*
* @param name the DB filename.
* @return RT_EOK:success
* -RT_ERROR:the input name is too long
*/
int db_connect(char *name);
/**
* This function will disconnect DB
*
* @param name the DB filename.
* @return RT_EOK:success
* -RT_ERROR:the input name is too long
*/
int db_disconnect(char *name);
/**
* This function will connect DB
*
* @param name the DB filename.
* @return 0:success
* -1:the input name is too long
*/
int db_set_name(char *name);
/**
* This function will get the current DB filename
*
* @return the current DB filename
*
*/
char *db_get_name(void);
#endif

View File

@ -0,0 +1,467 @@
static int _rtthread_io_read(sqlite3_file *file_id, void *pbuf, int cnt, sqlite3_int64 offset)
{
RTTHREAD_SQLITE_FILE_T *file = (RTTHREAD_SQLITE_FILE_T*)file_id;
sqlite3_int64 new_offset;
int r_cnt;
assert(file_id);
assert(offset >= 0);
assert(cnt > 0);
new_offset = lseek(file->fd, offset, SEEK_SET);
if (new_offset != offset)
{
return SQLITE_IOERR_READ;
}
do {
r_cnt = read(file->fd, pbuf, cnt);
if (r_cnt == cnt)
{
break;
}
if (r_cnt < 0)
{
if (errno != EINTR)
{
return SQLITE_IOERR_READ;
}
r_cnt = 1;
continue;
}
else if (r_cnt > 0)
{
cnt -= r_cnt;
pbuf = (void*)(r_cnt + (char*)pbuf);
}
} while (r_cnt > 0);
if (r_cnt != cnt)
{
memset(&((char*)pbuf)[r_cnt], 0, cnt - r_cnt);
return SQLITE_IOERR_SHORT_READ;
}
return SQLITE_OK;
}
static int _rtthread_io_write(sqlite3_file* file_id, const void *pbuf, int cnt, sqlite3_int64 offset)
{
RTTHREAD_SQLITE_FILE_T *file = (RTTHREAD_SQLITE_FILE_T*)file_id;
sqlite3_int64 new_offset;
int w_cnt;
assert(file_id);
assert(cnt > 0);
new_offset = lseek(file->fd, offset, SEEK_SET);
if (new_offset != offset)
{
return SQLITE_IOERR_WRITE;
}
do {
w_cnt = write(file->fd, pbuf, cnt);
if (w_cnt == cnt)
{
break;
}
if (w_cnt < 0)
{
if (errno != EINTR)
{
return SQLITE_IOERR_WRITE;
}
w_cnt = 1;
continue;
}
else if (w_cnt > 0)
{
cnt -= w_cnt;
pbuf = (void*)(w_cnt + (char*)pbuf);
}
} while (w_cnt > 0);
if (w_cnt != cnt)
{
return SQLITE_FULL;
}
return SQLITE_OK;
}
static int _rtthread_io_truncate(sqlite3_file* file_id, sqlite3_int64 size)
{
return SQLITE_IOERR_TRUNCATE;
}
static int _rtthread_io_sync(sqlite3_file* file_id, int flags)
{
RTTHREAD_SQLITE_FILE_T *file = (RTTHREAD_SQLITE_FILE_T*)file_id;
assert((flags & 0x0F) == SQLITE_SYNC_NORMAL
|| (flags & 0x0F) == SQLITE_SYNC_FULL);
fsync(file->fd);
return SQLITE_OK;
}
static int _rtthread_io_file_size(sqlite3_file* file_id, sqlite3_int64 *psize)
{
int rc;
struct stat buf;
RTTHREAD_SQLITE_FILE_T *file = (RTTHREAD_SQLITE_FILE_T*)file_id;
assert(file_id);
rc = fstat(file->fd, &buf);
if (rc != 0)
{
return SQLITE_IOERR_FSTAT;
}
*psize = buf.st_size;
/* When opening a zero-size database, the findInodeInfo() procedure
** writes a single byte into that file in order to work around a bug
** in the OS-X msdos filesystem. In order to avoid problems with upper
** layers, we need to report this file size as zero even though it is
** really 1. Ticket #3260.
*/
if (*psize == 1) *psize = 0;
return SQLITE_OK;
}
/*
** This routine checks if there is a RESERVED lock held on the specified
** file by this or any other process. If such a lock is held, set *pResOut
** to a non-zero value otherwise *pResOut is set to zero. The return value
** is set to SQLITE_OK unless an I/O error occurs during lock checking.
*/
static int _rtthread_io_check_reserved_lock(sqlite3_file *file_id, int *pResOut)
{
RTTHREAD_SQLITE_FILE_T *file = (RTTHREAD_SQLITE_FILE_T*)file_id;
rt_sem_t psem = &file->sem;
int reserved = 0;
/* Check if a thread in this process holds such a lock */
if (file->eFileLock > SHARED_LOCK)
{
reserved = 1;
}
/* Otherwise see if some other process holds it. */
if (!reserved)
{
if (rt_sem_trytake(psem) != RT_EOK)
{
/* someone else has the lock when we are in NO_LOCK */
reserved = (file->eFileLock < SHARED_LOCK);
}
else
{
/* we could have it if we want it */
rt_sem_release(psem);
}
}
*pResOut = reserved;
return SQLITE_OK;
}
/*
** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
** (2) RESERVED_LOCK
** (3) PENDING_LOCK
** (4) EXCLUSIVE_LOCK
**
** Sometimes when requesting one lock state, additional lock states
** are inserted in between. The locking might fail on one of the later
** transitions leaving the lock state different from what it started but
** still short of its goal. The following chart shows the allowed
** transitions and the inserted intermediate states:
**
** UNLOCKED -> SHARED
** SHARED -> RESERVED
** SHARED -> (PENDING) -> EXCLUSIVE
** RESERVED -> (PENDING) -> EXCLUSIVE
** PENDING -> EXCLUSIVE
**
** Semaphore locks only really support EXCLUSIVE locks. We track intermediate
** lock states in the sqlite3_file structure, but all locks SHARED or
** above are really EXCLUSIVE locks and exclude all other processes from
** access the file.
**
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
static int _rtthread_io_lock(sqlite3_file *file_id, int eFileLock)
{
RTTHREAD_SQLITE_FILE_T *file = (RTTHREAD_SQLITE_FILE_T*)file_id;
rt_sem_t psem = &file->sem;
int rc = SQLITE_OK;
/* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
if (file->eFileLock > NO_LOCK)
{
file->eFileLock = eFileLock;
rc = SQLITE_OK;
goto sem_end_lock;
}
/* lock semaphore now but bail out when already locked. */
if (rt_sem_trytake(psem) != RT_EOK)
{
rc = SQLITE_BUSY;
goto sem_end_lock;
}
/* got it, set the type and return ok */
file->eFileLock = eFileLock;
sem_end_lock:
return rc;
}
/*
** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
static int _rtthread_io_unlock(sqlite3_file *file_id, int eFileLock)
{
RTTHREAD_SQLITE_FILE_T *file = (RTTHREAD_SQLITE_FILE_T*)file_id;
rt_sem_t psem = &file->sem;
assert(eFileLock <= SHARED_LOCK);
/* no-op if possible */
if (file->eFileLock == eFileLock)
{
return SQLITE_OK;
}
/* shared can just be set because we always have an exclusive */
if (eFileLock == SHARED_LOCK)
{
file->eFileLock = SHARED_LOCK;
return SQLITE_OK;
}
/* no, really unlock. */
rt_sem_release(psem);
file->eFileLock = NO_LOCK;
return SQLITE_OK;
}
static int _rtthread_io_close(sqlite3_file *file_id)
{
int rc = 0;
RTTHREAD_SQLITE_FILE_T *file = (RTTHREAD_SQLITE_FILE_T*)file_id;
if (file->fd >= 0)
{
_rtthread_io_unlock(file_id, NO_LOCK);
rt_sem_detach(&file->sem);
rc = close(file->fd);
file->fd = -1;
}
return rc;
}
static int _rtthread_fcntl_size_hint(sqlite3_file *file_id, i64 nByte)
{
RTTHREAD_SQLITE_FILE_T *file = (RTTHREAD_SQLITE_FILE_T*)file_id;
if (file->szChunk > 0)
{
i64 nSize; /* Required file size */
struct stat buf; /* Used to hold return values of fstat() */
if (fstat(file->fd, &buf))
{
return SQLITE_IOERR_FSTAT;
}
nSize = ((nByte + file->szChunk - 1) / file->szChunk) * file->szChunk;
if (nSize > (i64)buf.st_size)
{
/* If the OS does not have posix_fallocate(), fake it. Write a
** single byte to the last byte in each block that falls entirely
** within the extended region. Then, if required, a single byte
** at offset (nSize-1), to set the size of the file correctly.
** This is a similar technique to that used by glibc on systems
** that do not have a real fallocate() call.
*/
int nBlk = 512; /* File-system block size */
int nWrite = 0; /* Number of bytes written by seekAndWrite */
i64 iWrite; /* Next offset to write to */
iWrite = (buf.st_size / nBlk) * nBlk + nBlk - 1;
assert(iWrite >= buf.st_size);
assert(((iWrite + 1) % nBlk) == 0);
for (/*no-op*/; iWrite < nSize + nBlk - 1; iWrite += nBlk)
{
if (iWrite >= nSize)
{
iWrite = nSize - 1;
}
nWrite = _rtthread_io_write(file_id, "", 1, iWrite);
if (nWrite != 1)
{
return SQLITE_IOERR_WRITE;
}
}
}
}
return SQLITE_OK;
}
/*
** Information and control of an open file handle.
*/
static int _rtthread_io_file_ctrl(sqlite3_file *file_id, int op, void *pArg)
{
RTTHREAD_SQLITE_FILE_T *file = (RTTHREAD_SQLITE_FILE_T*)file_id;
switch( op )
{
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = file->eFileLock;
return SQLITE_OK;
}
case SQLITE_LAST_ERRNO: {
*(int*)pArg = 0;
return SQLITE_OK;
}
case SQLITE_FCNTL_CHUNK_SIZE: {
file->szChunk = *(int *)pArg;
return SQLITE_OK;
}
case SQLITE_FCNTL_SIZE_HINT: {
int rc;
rc = _rtthread_fcntl_size_hint(file_id, *(i64 *)pArg);
return rc;
}
case SQLITE_FCNTL_PERSIST_WAL: {
return SQLITE_OK;
}
case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
return SQLITE_OK;
}
case SQLITE_FCNTL_VFSNAME: {
*(char**)pArg = sqlite3_mprintf("%s", file->pvfs->zName);
return SQLITE_OK;
}
case SQLITE_FCNTL_TEMPFILENAME: {
char *zTFile = sqlite3_malloc(file->pvfs->mxPathname );
if( zTFile )
{
_rtthread_get_temp_name(file->pvfs->mxPathname, zTFile);
*(char**)pArg = zTFile;
}
return SQLITE_OK;
}
}
return SQLITE_NOTFOUND;
}
static int _rtthread_io_sector_size(sqlite3_file *file_id)
{
return SQLITE_DEFAULT_SECTOR_SIZE;
}
static int _rtthread_io_device_characteristics(sqlite3_file *file_id)
{
return 0;
}
/*
** If possible, return a pointer to a mapping of file fd starting at offset
** iOff. The mapping must be valid for at least nAmt bytes.
**
** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
** Finally, if an error does occur, return an SQLite error code. The final
** value of *pp is undefined in this case.
**
** If this function does return a pointer, the caller must eventually
** release the reference by calling unixUnfetch().
*/
static int _rtthread_io_fetch(sqlite3_file *file_id, i64 iOff, int nAmt, void **pp)
{
*pp = 0;
return SQLITE_OK;
}
/*
** If the third argument is non-NULL, then this function releases a
** reference obtained by an earlier call to unixFetch(). The second
** argument passed to this function must be the same as the corresponding
** argument that was passed to the unixFetch() invocation.
**
** Or, if the third argument is NULL, then this function is being called
** to inform the VFS layer that, according to POSIX, any existing mapping
** may now be invalid and should be unmapped.
*/
static int _rtthread_io_unfetch(sqlite3_file *fd, i64 iOff, void *p)
{
return SQLITE_OK;
}
static const sqlite3_io_methods _rtthread_io_method = {
3,
_rtthread_io_close,
_rtthread_io_read,
_rtthread_io_write,
_rtthread_io_truncate,
_rtthread_io_sync,
_rtthread_io_file_size,
_rtthread_io_lock,
_rtthread_io_unlock,
_rtthread_io_check_reserved_lock,
_rtthread_io_file_ctrl,
_rtthread_io_sector_size,
_rtthread_io_device_characteristics,
0,
0,
0,
0,
_rtthread_io_fetch,
_rtthread_io_unfetch
};

View File

@ -0,0 +1,228 @@
#if defined(SQLITE_MUTEX_RTTHREAD)
/*
* rt-thread mutex
*/
struct sqlite3_mutex {
struct rt_mutex mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
};
SQLITE_PRIVATE void sqlite3MemoryBarrier(void)
{
}
/*
** Initialize and deinitialize the mutex subsystem.
The argument to sqlite3_mutex_alloc() must one of these integer constants:
SQLITE_MUTEX_FAST
SQLITE_MUTEX_RECURSIVE
SQLITE_MUTEX_STATIC_MASTER
SQLITE_MUTEX_STATIC_MEM
SQLITE_MUTEX_STATIC_OPEN
SQLITE_MUTEX_STATIC_PRNG
SQLITE_MUTEX_STATIC_LRU
SQLITE_MUTEX_STATIC_PMEM
SQLITE_MUTEX_STATIC_APP1
SQLITE_MUTEX_STATIC_APP2
SQLITE_MUTEX_STATIC_APP3
SQLITE_MUTEX_STATIC_VFS1
SQLITE_MUTEX_STATIC_VFS2
SQLITE_MUTEX_STATIC_VFS3
The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
cause sqlite3_mutex_alloc() to create a new mutex. The new mutex is recursive
when SQLITE_MUTEX_RECURSIVE is used but not necessarily so when SQLITE_MUTEX_FAST
is used. The mutex implementation does not need to make a distinction between
SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does not want to.
SQLite will only request a recursive mutex in cases where it really needs one.
If a faster non-recursive mutex implementation is available on the host platform,
the mutex subsystem might return such a mutex in response to SQLITE_MUTEX_FAST.
The other allowed parameters to sqlite3_mutex_alloc()
(anything other than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return
a pointer to a static preexisting mutex. Nine static mutexes are used by the
current version of SQLite. Future versions of SQLite may add additional static
mutexes. Static mutexes are for internal use by SQLite only. Applications that
use SQLite mutexes should use only the dynamic mutexes returned by SQLITE_MUTEX_FAST
or SQLITE_MUTEX_RECURSIVE.
Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST or SQLITE_MUTEX_RECURSIVE)
is used then sqlite3_mutex_alloc() returns a different mutex on every call.
For the static mutex types, the same mutex is returned on every call that has the same type number.
*/
static sqlite3_mutex _static_mutex[12];
static int _rtthread_mtx_init(void)
{
int i;
rt_err_t err;
for (i = 0; i < sizeof(_static_mutex) / sizeof(_static_mutex[0]); i++)
{
err = rt_mutex_init(&_static_mutex[i].mutex, "sqlmtx", RT_IPC_FLAG_PRIO);
if (err != RT_EOK)
{
return SQLITE_ERROR;
}
}
return SQLITE_OK;
}
static int _rtthread_mtx_end(void)
{
int i;
rt_err_t err;
for (i = 0; i < sizeof(_static_mutex) / sizeof(_static_mutex[0]); i++)
{
err = rt_mutex_detach(&_static_mutex[i].mutex);
_static_mutex[i].mutex.owner = 0;
_static_mutex[i].mutex.hold = 0;
if (err != RT_EOK)
{
return SQLITE_ERROR;
}
}
return SQLITE_OK;
}
static sqlite3_mutex * _rtthread_mtx_alloc(int id)
{
sqlite3_mutex *p = NULL;
switch (id)
{
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE:
p = sqlite3Malloc(sizeof(sqlite3_mutex));
if (p != NULL)
{
rt_mutex_init(&p->mutex, "sqlmtx", RT_IPC_FLAG_PRIO);
p->id = id;
}
break;
default:
assert(id - 2 >= 0);
assert(id - 2 < ArraySize(_static_mutex) );
p = &_static_mutex[id - 2];
p->id = id;
break;
}
return p;
}
static void _rtthread_mtx_free(sqlite3_mutex * p)
{
assert(p != 0);
rt_mutex_detach(&p->mutex);
switch (p->id)
{
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE:
sqlite3_free(p);
break;
default:
break;
}
}
static void _rtthread_mtx_enter(sqlite3_mutex *p)
{
assert(p != 0);
rt_mutex_take(&p->mutex, RT_WAITING_FOREVER);
}
static int _rtthread_mtx_try(sqlite3_mutex *p)
{
assert(p != 0);
if (rt_mutex_take(&p->mutex, RT_WAITING_NO) != RT_EOK)
{
return SQLITE_BUSY;
}
return SQLITE_OK;
}
static void _rtthread_mtx_leave(sqlite3_mutex *p)
{
assert(p != 0);
rt_mutex_release(&p->mutex);
}
#ifdef SQLITE_DEBUG
/*
If the argument to sqlite3_mutex_held() is a NULL pointer then the routine
should return 1. This seems counter-intuitive since clearly the mutex cannot
be held if it does not exist. But the reason the mutex does not exist is
because the build is not using mutexes. And we do not want the assert()
containing the call to sqlite3_mutex_held() to fail, so a non-zero return
is the appropriate thing to do. The sqlite3_mutex_notheld() interface should
also return 1 when given a NULL pointer.
*/
static int _rtthread_mtx_held(sqlite3_mutex *p)
{
if (p != 0)
{
if ((rt_thread_self() == p->mutex.owner) && (p->mutex.hold > 0))
{
return 1;
}
return 0;
}
return 1;
}
static int _rtthread_mtx_noheld(sqlite3_mutex *p)
{
if (_rtthread_mtx_held(p))
{
return 0;
}
return 1;
}
#endif /* SQLITE_DEBUG */
SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void)
{
static const sqlite3_mutex_methods sMutex = {
_rtthread_mtx_init,
_rtthread_mtx_end,
_rtthread_mtx_alloc,
_rtthread_mtx_free,
_rtthread_mtx_enter,
_rtthread_mtx_try,
_rtthread_mtx_leave,
#ifdef SQLITE_DEBUG
_rtthread_mtx_held,
_rtthread_mtx_noheld
#else
0,
0
#endif
};
return &sMutex;
}
#endif /* SQLITE_MUTEX_RTTHREAD */

View File

@ -0,0 +1,654 @@
#ifdef SQLITE_OS_RTTHREAD
#ifndef SQLITE_OMIT_LOAD_EXTENSION
#error "rt-thread not support load extension, compile with SQLITE_OMIT_LOAD_EXTENSION."
#endif
#define RTTHREAD_MAX_PATHNAME 256
#include <dfs_posix.h>
/*
** Define various macros that are missing from some systems.
*/
#ifndef O_LARGEFILE
# define O_LARGEFILE 0
#endif
#ifdef SQLITE_DISABLE_LFS
# undef O_LARGEFILE
# define O_LARGEFILE 0
#endif
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
#ifndef RT_USING_NEWLIB
#ifndef EINTR
#define EINTR 4 /* Interrupted system call */
#endif
#ifndef ENOLCK
#define ENOLCK 46 /* No record locks available */
#endif
#ifndef EACCES
#define EACCES 13 /* Permission denied */
#endif
#ifndef EPERM
#define EPERM 1 /* Operation not permitted */
#endif
#ifndef ETIMEDOUT
#define ETIMEDOUT 145 /* Connection timed out */
#endif
#ifndef ENOTCONN
#define ENOTCONN 134 /* Transport endpoint is not connected */
#endif
#if defined(__GNUC__) || defined(__ADSPBLACKFIN__)
int _gettimeofday(struct timeval *tp, void *ignore) __attribute__((weak));
int _gettimeofday(struct timeval *tp, void *ignore)
#elif defined(__CC_ARM)
__weak int _gettimeofday(struct timeval *tp, void *ignore)
#elif defined(__IAR_SYSTEMS_ICC__)
#if __VER__ > 540
__weak
#endif
int _gettimeofday(struct timeval *tp, void *ignore)
#else
int _gettimeofday(struct timeval *tp, void *ignore)
#endif
{
return 0;
}
#endif /* RT_USING_NEWLIB */
static int _Access(const char *pathname, int mode)
{
int fd;
fd = open(pathname, O_RDONLY, mode);
if (fd >= 0)
{
close(fd);
return 0;
}
return -1;
}
#define _RTTHREAD_LOG_ERROR(a,b,c) _rtthread_log_error_at_line(a,b,c,__LINE__)
static int _rtthread_log_error_at_line(
int errcode, /* SQLite error code */
const char *zFunc, /* Name of OS function that failed */
const char *zPath, /* File path associated with error */
int iLine /* Source line number where error occurred */
)
{
char *zErr; /* Message from strerror() or equivalent */
int iErrno = errno; /* Saved syscall error number */
/* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
** the strerror() function to obtain the human-readable error message
** equivalent to errno. Otherwise, use strerror_r().
*/
#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
char aErr[80];
memset(aErr, 0, sizeof(aErr));
zErr = aErr;
/* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined,
** assume that the system provides the GNU version of strerror_r() that
** returns a pointer to a buffer containing the error message. That pointer
** may point to aErr[], or it may point to some static storage somewhere.
** Otherwise, assume that the system provides the POSIX version of
** strerror_r(), which always writes an error message into aErr[].
**
** If the code incorrectly assumes that it is the POSIX version that is
** available, the error message will often be an empty string. Not a
** huge problem. Incorrectly concluding that the GNU version is available
** could lead to a segfault though.
*/
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
zErr =
#endif
strerror_r(iErrno, aErr, sizeof(aErr)-1);
#elif SQLITE_THREADSAFE
/* This is a threadsafe build, but strerror_r() is not available. */
zErr = "";
#else
/* Non-threadsafe build, use strerror(). */
zErr = strerror(iErrno);
#endif
if( zPath==0 )
zPath = "";
sqlite3_log(errcode, "os_rtthread.c:%d: (%d) %s(%s) - %s",
iLine, iErrno, zFunc, zPath, zErr);
return errcode;
}
typedef struct
{
sqlite3_io_methods const *pMethod;
sqlite3_vfs *pvfs;
int fd;
int eFileLock;
int szChunk;
struct rt_semaphore sem;
} RTTHREAD_SQLITE_FILE_T;
static const char* _rtthread_temp_file_dir(void)
{
const char *azDirs[] = {
0,
"/sql",
"/sql/tmp"
"/tmp",
0 /* List terminator */
};
unsigned int i;
struct stat buf;
const char *zDir = 0;
azDirs[0] = sqlite3_temp_directory;
for (i = 0; i < sizeof(azDirs) / sizeof(azDirs[0]); zDir = azDirs[i++])
{
if( zDir == 0 ) continue;
if( stat(zDir, &buf) ) continue;
if( !S_ISDIR(buf.st_mode) ) continue;
break;
}
return zDir;
}
/*
** Create a temporary file name in zBuf. zBuf must be allocated
** by the calling process and must be big enough to hold at least
** pVfs->mxPathname bytes.
*/
static int _rtthread_get_temp_name(int nBuf, char *zBuf)
{
const unsigned char zChars[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
unsigned int i, j;
const char *zDir;
zDir = _rtthread_temp_file_dir();
if (zDir == 0)
{
zDir = ".";
}
/* Check that the output buffer is large enough for the temporary file
** name. If it is not, return SQLITE_ERROR.
*/
if ((strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf)
{
return SQLITE_ERROR;
}
do {
sqlite3_snprintf(nBuf-18, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
j = (int)strlen(zBuf);
sqlite3_randomness(15, &zBuf[j]);
for (i = 0; i < 15; i++, j++)
{
zBuf[j] = (char)zChars[((unsigned char)zBuf[j]) % (sizeof(zChars) - 1)];
}
zBuf[j] = 0;
zBuf[j + 1] = 0;
} while (_Access(zBuf, 0) == 0);
return SQLITE_OK;
}
#include "rtthread_io_methods.c"
/*
** Invoke open(). Do so multiple times, until it either succeeds or
** fails for some reason other than EINTR.
**
** If the file creation mode "m" is 0 then set it to the default for
** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
** 0644) as modified by the system umask. If m is not 0, then
** make the file creation mode be exactly m ignoring the umask.
**
** The m parameter will be non-zero only when creating -wal, -journal,
** and -shm files. We want those files to have *exactly* the same
** permissions as their original database, unadulterated by the umask.
** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
** transaction crashes and leaves behind hot journals, then any
** process that is able to write to the database will also be able to
** recover the hot journals.
*/
static int _rtthread_fs_open(const char *file_path, int f, mode_t m)
{
int fd = -1;
while (fd < 0)
{
#if defined(O_CLOEXEC)
fd = open(file_path, f | O_CLOEXEC, m);
#else
fd = open(file_path, f, m);
#endif
if (fd < 0)
{
if (errno == EINTR)
continue;
break;
}
}
return fd;
}
static int _rtthread_vfs_open(sqlite3_vfs *pvfs, const char *file_path, sqlite3_file *file_id, int flags, int *pOutFlags)
{
RTTHREAD_SQLITE_FILE_T *p;
int fd;
int eType = flags & 0xFFFFFF00; /* Type of file to open */
int rc = SQLITE_OK; /* Function Return Code */
int openFlags = 0;
mode_t openMode = 0;
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
int isCreate = (flags & SQLITE_OPEN_CREATE);
int isReadonly = (flags & SQLITE_OPEN_READONLY);
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
/* If argument zPath is a NULL pointer, this function is required to open
** a temporary file. Use this buffer to store the file name in.
*/
char zTmpname[RTTHREAD_MAX_PATHNAME + 2];
p = (RTTHREAD_SQLITE_FILE_T*)file_id;
/* Check the following statements are true:
**
** (a) Exactly one of the READWRITE and READONLY flags must be set, and
** (b) if CREATE is set, then READWRITE must also be set, and
** (c) if EXCLUSIVE is set, then CREATE must also be set.
** (d) if DELETEONCLOSE is set, then CREATE must also be set.
*/
assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
assert(isCreate==0 || isReadWrite);
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
/* The main DB, main journal, WAL file and master journal are never
** automatically deleted. Nor are they ever temporary files. */
assert( (!isDelete && file_path) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && file_path) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
assert( (!isDelete && file_path) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
assert( (!isDelete && file_path) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
|| eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
/* Database filenames are double-zero terminated if they are not
** URIs with parameters. Hence, they can always be passed into
** sqlite3_uri_parameter(). */
assert((eType != SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) || file_path[strlen(file_path) + 1] == 0);
memset(p, 0, sizeof(RTTHREAD_SQLITE_FILE_T));
if (!file_path)
{
rc = _rtthread_get_temp_name(RTTHREAD_MAX_PATHNAME + 2, zTmpname);
if (rc != SQLITE_OK )
{
return rc;
}
file_path = zTmpname;
/* Generated temporary filenames are always double-zero terminated
** for use by sqlite3_uri_parameter(). */
assert(file_path[strlen(file_path) + 1] == 0);
}
/* Determine the value of the flags parameter passed to POSIX function
** open(). These must be calculated even if open() is not called, as
** they may be stored as part of the file handle and used by the
** 'conch file' locking functions later on. */
if (isReadonly) openFlags |= O_RDONLY;
if (isReadWrite) openFlags |= O_RDWR;
if (isCreate) openFlags |= O_CREAT;
if (isExclusive) openFlags |= (O_EXCL | O_NOFOLLOW);
openFlags |= (O_LARGEFILE | O_BINARY);
fd = _rtthread_fs_open(file_path, openFlags, openMode);
if (fd < 0 && (errno != -EISDIR) && isReadWrite && !isExclusive)
{
/* Failed to open the file for read/write access. Try read-only. */
flags &= ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
openFlags &= ~(O_RDWR | O_CREAT);
flags |= SQLITE_OPEN_READONLY;
openFlags |= O_RDONLY;
isReadonly = 1;
fd = _rtthread_fs_open(file_path, openFlags, openMode);
}
if (fd < 0)
{
rc = _RTTHREAD_LOG_ERROR(SQLITE_CANTOPEN_BKPT, "open", file_path);
return rc;
}
if (pOutFlags)
{
*pOutFlags = flags;
}
if (isDelete)
{
unlink(file_path);
}
p->fd = fd;
p->pMethod = &_rtthread_io_method;
p->eFileLock = NO_LOCK;
p->szChunk = 0;
p->pvfs = pvfs;
rt_sem_init(&p->sem, "vfssem", 1, RT_IPC_FLAG_PRIO);
return rc;
}
int _rtthread_vfs_delete(sqlite3_vfs* pvfs, const char *file_path, int syncDir)
{
int rc = SQLITE_OK;
if (unlink(file_path) == (-1))
{
if (errno == -ENOENT)
{
rc = SQLITE_IOERR_DELETE_NOENT;
}
else
{
rc = _RTTHREAD_LOG_ERROR(SQLITE_IOERR_DELETE, "unlink", file_path);
}
return rc;
}
// sync dir: open dir -> fsync -> close
if ((syncDir & 1) != 0)
{
int ii;
int fd = -1;
char zDirname[RTTHREAD_MAX_PATHNAME + 1];
sqlite3_snprintf(RTTHREAD_MAX_PATHNAME, zDirname, "%s", file_path);
for (ii=(int)strlen(zDirname); ii > 1 && zDirname[ii] != '/'; ii--);
if (ii > 0)
{
zDirname[ii] = '\0';
fd = _rtthread_fs_open(zDirname, O_RDONLY | O_BINARY, 0);
}
if (fd >= 0)
{
if (fsync(fd))
{
rc = _RTTHREAD_LOG_ERROR(SQLITE_IOERR_DIR_FSYNC, "fsync", file_path);
}
close(fd);
}
rc = SQLITE_OK;
}
return rc;
}
static int _rtthread_vfs_access(sqlite3_vfs* pvfs, const char *file_path, int flags, int *pResOut)
{
int amode = 0;
#ifndef F_OK
# define F_OK 0
#endif
#ifndef R_OK
# define R_OK 4
#endif
#ifndef W_OK
# define W_OK 2
#endif
switch (flags)
{
case SQLITE_ACCESS_EXISTS:
amode = F_OK;
break;
case SQLITE_ACCESS_READWRITE:
amode = W_OK | R_OK;
break;
case SQLITE_ACCESS_READ:
amode = R_OK;
break;
default:
_RTTHREAD_LOG_ERROR(flags, "access", file_path);
return -1;
}
*pResOut = (_Access(file_path, amode) == 0);
if (flags == SQLITE_ACCESS_EXISTS && *pResOut)
{
struct stat buf;
if (0 == stat(file_path, &buf) && (buf.st_size == 0))
{
*pResOut = 0;
}
}
return SQLITE_OK;
}
static int _rtthread_vfs_fullpathname(sqlite3_vfs* pvfs, const char *file_path, int nOut, char *zOut)
{
assert(pvfs->mxPathname == RTTHREAD_MAX_PATHNAME);
zOut[nOut - 1] = '\0';
if (file_path[0] == '/')
{
sqlite3_snprintf(nOut, zOut, "%s", file_path);
}
else
{
int nCwd;
if (getcwd(zOut, nOut - 1) == 0)
{
return _RTTHREAD_LOG_ERROR(SQLITE_CANTOPEN_BKPT, "getcwd", file_path);
}
nCwd = (int)strlen(zOut);
sqlite3_snprintf(nOut - nCwd, &zOut[nCwd], "/%s", file_path);
}
return SQLITE_OK;
}
static int _rtthread_vfs_randomness(sqlite3_vfs* pvfs, int nByte, char *zOut)
{
assert((size_t)nByte >= (sizeof(time_t) + sizeof(int)));
memset(zOut, 0, nByte);
{
int i;
char tick8, tick16;
tick8 = (char)rt_tick_get();
tick16 = (char)(rt_tick_get() >> 8);
for (i = 0; i < nByte; i++)
{
zOut[i] = (char)(i ^ tick8 ^ tick16);
tick8 = zOut[i];
tick16 = ~(tick8 ^ tick16);
}
}
return nByte;
}
static int _rtthread_vfs_sleep(sqlite3_vfs* pvfs, int microseconds)
{
int millisecond = (microseconds + 999) / 1000;
rt_thread_delay(rt_tick_from_millisecond(millisecond));
return millisecond * 1000;
}
static int _rtthread_vfs_current_time_int64(sqlite3_vfs*, sqlite3_int64*);
static int _rtthread_vfs_current_time(sqlite3_vfs* pvfs, double* pnow)
{
sqlite3_int64 i = 0;
int rc;
rc = _rtthread_vfs_current_time_int64(0, &i);
*pnow = i / 86400000.0;
return rc;
}
static int _rtthread_vfs_get_last_error(sqlite3_vfs* pvfs, int nBuf, char *zBuf)
{
return 0;
}
static int _rtthread_vfs_current_time_int64(sqlite3_vfs* pvfs, sqlite3_int64*pnow)
{
#ifndef NO_GETTOD
#define NO_GETTOD 1
#endif
static const sqlite3_int64 rtthreadEpoch = 24405875 * (sqlite3_int64)8640000;
int rc = SQLITE_OK;
#if defined(NO_GETTOD)
time_t t;
time(&t);
*pnow = ((sqlite3_int64)t) * 1000 + rtthreadEpoch;
#else
struct timeval sNow;
if (gettimeofday(&sNow, 0) == 0)
{
*pnow = rtthreadEpoch + 1000 * (sqlite3_int64)sNow.tv_sec + sNow.tv_usec / 1000;
}
else
{
rc = SQLITE_ERROR;
}
#endif
#ifdef SQLITE_TEST
if( sqlite3_current_time )
{
*pnow = 1000 * (sqlite3_int64)sqlite3_current_time + rtthreadEpoch;
}
#endif
return rc;
}
static int _rtthread_vfs_set_system_call(sqlite3_vfs* pvfs, const char *file_path, sqlite3_syscall_ptr pfn)
{
return SQLITE_NOTFOUND;
}
static sqlite3_syscall_ptr _rtthread_vfs_get_system_call(sqlite3_vfs* pvfs, const char *file_path)
{
return 0;
}
static const char* _rtthread_vfs_next_system_call(sqlite3_vfs *pvfs, const char *file_path)
{
return 0;
}
/*
** Initialize and deinitialize the operating system interface.
*/
SQLITE_API int sqlite3_os_init(void)
{
static sqlite3_vfs _rtthread_vfs = {
3, /* iVersion */
sizeof(RTTHREAD_SQLITE_FILE_T), /* szOsFile */
RTTHREAD_MAX_PATHNAME, /* mxPathname */
0, /* pNext */
"rt-thread", /* zName */
0, /* pAppData */
_rtthread_vfs_open, /* xOpen */
_rtthread_vfs_delete, /* xDelete */
_rtthread_vfs_access, /* xAccess */
_rtthread_vfs_fullpathname, /* xFullPathname */
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
_rtthread_vfs_randomness, /* xRandomness */
_rtthread_vfs_sleep, /* xSleep */
_rtthread_vfs_current_time, /* xCurrentTime */
_rtthread_vfs_get_last_error, /* xGetLastError */
_rtthread_vfs_current_time_int64, /* xCurrentTimeInt64 */
_rtthread_vfs_set_system_call, /* xSetSystemCall */
_rtthread_vfs_get_system_call, /* xGetSystemCall */
_rtthread_vfs_next_system_call, /* xNextSystemCall */
};
sqlite3_vfs_register(&_rtthread_vfs, 1);
return SQLITE_OK;
}
SQLITE_API int sqlite3_os_end(void)
{
return SQLITE_OK;
}
#endif /* SQLITE_OS_RTTHREAD */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,564 @@
/*
** 2006 June 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance. Shared libraries that intend to be loaded
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
#ifndef SQLITE3EXT_H
#define SQLITE3EXT_H
#include "sqlite3.h"
/*
** The following structure holds pointers to all of the SQLite API
** routines.
**
** WARNING: In order to maintain backwards compatibility, add new
** interfaces to the end of this structure only. If you insert new
** interfaces in the middle of this structure, then older different
** versions of SQLite will not be able to load each other's shared
** libraries!
*/
struct sqlite3_api_routines {
void * (*aggregate_context)(sqlite3_context*,int nBytes);
int (*aggregate_count)(sqlite3_context*);
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
int (*bind_double)(sqlite3_stmt*,int,double);
int (*bind_int)(sqlite3_stmt*,int,int);
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
int (*bind_null)(sqlite3_stmt*,int);
int (*bind_parameter_count)(sqlite3_stmt*);
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
int (*busy_timeout)(sqlite3*,int ms);
int (*changes)(sqlite3*);
int (*close)(sqlite3*);
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const void*));
const void * (*column_blob)(sqlite3_stmt*,int iCol);
int (*column_bytes)(sqlite3_stmt*,int iCol);
int (*column_bytes16)(sqlite3_stmt*,int iCol);
int (*column_count)(sqlite3_stmt*pStmt);
const char * (*column_database_name)(sqlite3_stmt*,int);
const void * (*column_database_name16)(sqlite3_stmt*,int);
const char * (*column_decltype)(sqlite3_stmt*,int i);
const void * (*column_decltype16)(sqlite3_stmt*,int);
double (*column_double)(sqlite3_stmt*,int iCol);
int (*column_int)(sqlite3_stmt*,int iCol);
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
const char * (*column_name)(sqlite3_stmt*,int);
const void * (*column_name16)(sqlite3_stmt*,int);
const char * (*column_origin_name)(sqlite3_stmt*,int);
const void * (*column_origin_name16)(sqlite3_stmt*,int);
const char * (*column_table_name)(sqlite3_stmt*,int);
const void * (*column_table_name16)(sqlite3_stmt*,int);
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
const void * (*column_text16)(sqlite3_stmt*,int iCol);
int (*column_type)(sqlite3_stmt*,int iCol);
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
int (*complete)(const char*sql);
int (*complete16)(const void*sql);
int (*create_collation)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_collation16)(sqlite3*,const void*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_function)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_function16)(sqlite3*,const void*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
int (*data_count)(sqlite3_stmt*pStmt);
sqlite3 * (*db_handle)(sqlite3_stmt*);
int (*declare_vtab)(sqlite3*,const char*);
int (*enable_shared_cache)(int);
int (*errcode)(sqlite3*db);
const char * (*errmsg)(sqlite3*);
const void * (*errmsg16)(sqlite3*);
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
int (*expired)(sqlite3_stmt*);
int (*finalize)(sqlite3_stmt*pStmt);
void (*free)(void*);
void (*free_table)(char**result);
int (*get_autocommit)(sqlite3*);
void * (*get_auxdata)(sqlite3_context*,int);
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
int (*global_recover)(void);
void (*interruptx)(sqlite3*);
sqlite_int64 (*last_insert_rowid)(sqlite3*);
const char * (*libversion)(void);
int (*libversion_number)(void);
void *(*malloc)(int);
char * (*mprintf)(const char*,...);
int (*open)(const char*,sqlite3**);
int (*open16)(const void*,sqlite3**);
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
void *(*realloc)(void*,int);
int (*reset)(sqlite3_stmt*pStmt);
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_double)(sqlite3_context*,double);
void (*result_error)(sqlite3_context*,const char*,int);
void (*result_error16)(sqlite3_context*,const void*,int);
void (*result_int)(sqlite3_context*,int);
void (*result_int64)(sqlite3_context*,sqlite_int64);
void (*result_null)(sqlite3_context*);
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_value)(sqlite3_context*,sqlite3_value*);
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*snprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
void (*thread_cleanup)(void);
int (*total_changes)(sqlite3*);
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
sqlite_int64),void*);
void * (*user_data)(sqlite3_context*);
const void * (*value_blob)(sqlite3_value*);
int (*value_bytes)(sqlite3_value*);
int (*value_bytes16)(sqlite3_value*);
double (*value_double)(sqlite3_value*);
int (*value_int)(sqlite3_value*);
sqlite_int64 (*value_int64)(sqlite3_value*);
int (*value_numeric_type)(sqlite3_value*);
const unsigned char * (*value_text)(sqlite3_value*);
const void * (*value_text16)(sqlite3_value*);
const void * (*value_text16be)(sqlite3_value*);
const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*);
char *(*vmprintf)(const char*,va_list);
/* Added ??? */
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
/* Added by 3.3.13 */
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
int (*clear_bindings)(sqlite3_stmt*);
/* Added by 3.4.1 */
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
void (*xDestroy)(void *));
/* Added by 3.5.0 */
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
int (*blob_bytes)(sqlite3_blob*);
int (*blob_close)(sqlite3_blob*);
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
int,sqlite3_blob**);
int (*blob_read)(sqlite3_blob*,void*,int,int);
int (*blob_write)(sqlite3_blob*,const void*,int,int);
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*),
void(*)(void*));
int (*file_control)(sqlite3*,const char*,int,void*);
sqlite3_int64 (*memory_highwater)(int);
sqlite3_int64 (*memory_used)(void);
sqlite3_mutex *(*mutex_alloc)(int);
void (*mutex_enter)(sqlite3_mutex*);
void (*mutex_free)(sqlite3_mutex*);
void (*mutex_leave)(sqlite3_mutex*);
int (*mutex_try)(sqlite3_mutex*);
int (*open_v2)(const char*,sqlite3**,int,const char*);
int (*release_memory)(int);
void (*result_error_nomem)(sqlite3_context*);
void (*result_error_toobig)(sqlite3_context*);
int (*sleep)(int);
void (*soft_heap_limit)(int);
sqlite3_vfs *(*vfs_find)(const char*);
int (*vfs_register)(sqlite3_vfs*,int);
int (*vfs_unregister)(sqlite3_vfs*);
int (*xthreadsafe)(void);
void (*result_zeroblob)(sqlite3_context*,int);
void (*result_error_code)(sqlite3_context*,int);
int (*test_control)(int, ...);
void (*randomness)(int,void*);
sqlite3 *(*context_db_handle)(sqlite3_context*);
int (*extended_result_codes)(sqlite3*,int);
int (*limit)(sqlite3*,int,int);
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
const char *(*sql)(sqlite3_stmt*);
int (*status)(int,int*,int*,int);
int (*backup_finish)(sqlite3_backup*);
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
int (*backup_pagecount)(sqlite3_backup*);
int (*backup_remaining)(sqlite3_backup*);
int (*backup_step)(sqlite3_backup*,int);
const char *(*compileoption_get)(int);
int (*compileoption_used)(const char*);
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void(*xDestroy)(void*));
int (*db_config)(sqlite3*,int,...);
sqlite3_mutex *(*db_mutex)(sqlite3*);
int (*db_status)(sqlite3*,int,int*,int*,int);
int (*extended_errcode)(sqlite3*);
void (*log)(int,const char*,...);
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
const char *(*sourceid)(void);
int (*stmt_status)(sqlite3_stmt*,int,int);
int (*strnicmp)(const char*,const char*,int);
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
int (*wal_autocheckpoint)(sqlite3*,int);
int (*wal_checkpoint)(sqlite3*,const char*);
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
int (*vtab_config)(sqlite3*,int op,...);
int (*vtab_on_conflict)(sqlite3*);
/* Version 3.7.16 and later */
int (*close_v2)(sqlite3*);
const char *(*db_filename)(sqlite3*,const char*);
int (*db_readonly)(sqlite3*,const char*);
int (*db_release_memory)(sqlite3*);
const char *(*errstr)(int);
int (*stmt_busy)(sqlite3_stmt*);
int (*stmt_readonly)(sqlite3_stmt*);
int (*stricmp)(const char*,const char*);
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
char *(*vsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
void(*)(void*));
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
void(*)(void*),unsigned char);
int (*cancel_auto_extension)(void(*)(void));
int (*load_extension)(sqlite3*,const char*,const char*,char**);
void *(*malloc64)(sqlite3_uint64);
sqlite3_uint64 (*msize)(void*);
void *(*realloc64)(void*,sqlite3_uint64);
void (*reset_auto_extension)(void);
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
void(*)(void*));
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
void(*)(void*), unsigned char);
int (*strglob)(const char*,const char*);
/* Version 3.8.11 and later */
sqlite3_value *(*value_dup)(const sqlite3_value*);
void (*value_free)(sqlite3_value*);
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
/* Version 3.9.0 and later */
unsigned int (*value_subtype)(sqlite3_value*);
void (*result_subtype)(sqlite3_context*,unsigned int);
/* Version 3.10.0 and later */
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
int (*strlike)(const char*,const char*,unsigned int);
int (*db_cacheflush)(sqlite3*);
/* Version 3.12.0 and later */
int (*system_errno)(sqlite3*);
/* Version 3.14.0 and later */
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
char *(*expanded_sql)(sqlite3_stmt*);
/* Version 3.18.0 and later */
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
sqlite3 *db, /* Handle to the database. */
char **pzErrMsg, /* Used to set error string on failure. */
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
);
/*
** The following macros redefine the API routines so that they are
** redirected through the global sqlite3_api structure.
**
** This header file is also used by the loadext.c source file
** (part of the main SQLite library - not an extension) so that
** it can get access to the sqlite3_api_routines structure
** definition. But the main library does not want to redefine
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
#endif
#define sqlite3_bind_blob sqlite3_api->bind_blob
#define sqlite3_bind_double sqlite3_api->bind_double
#define sqlite3_bind_int sqlite3_api->bind_int
#define sqlite3_bind_int64 sqlite3_api->bind_int64
#define sqlite3_bind_null sqlite3_api->bind_null
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
#define sqlite3_bind_text sqlite3_api->bind_text
#define sqlite3_bind_text16 sqlite3_api->bind_text16
#define sqlite3_bind_value sqlite3_api->bind_value
#define sqlite3_busy_handler sqlite3_api->busy_handler
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
#define sqlite3_changes sqlite3_api->changes
#define sqlite3_close sqlite3_api->close
#define sqlite3_collation_needed sqlite3_api->collation_needed
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
#define sqlite3_column_blob sqlite3_api->column_blob
#define sqlite3_column_bytes sqlite3_api->column_bytes
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
#define sqlite3_column_count sqlite3_api->column_count
#define sqlite3_column_database_name sqlite3_api->column_database_name
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
#define sqlite3_column_decltype sqlite3_api->column_decltype
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
#define sqlite3_column_double sqlite3_api->column_double
#define sqlite3_column_int sqlite3_api->column_int
#define sqlite3_column_int64 sqlite3_api->column_int64
#define sqlite3_column_name sqlite3_api->column_name
#define sqlite3_column_name16 sqlite3_api->column_name16
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
#define sqlite3_column_table_name sqlite3_api->column_table_name
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
#define sqlite3_column_text sqlite3_api->column_text
#define sqlite3_column_text16 sqlite3_api->column_text16
#define sqlite3_column_type sqlite3_api->column_type
#define sqlite3_column_value sqlite3_api->column_value
#define sqlite3_commit_hook sqlite3_api->commit_hook
#define sqlite3_complete sqlite3_api->complete
#define sqlite3_complete16 sqlite3_api->complete16
#define sqlite3_create_collation sqlite3_api->create_collation
#define sqlite3_create_collation16 sqlite3_api->create_collation16
#define sqlite3_create_function sqlite3_api->create_function
#define sqlite3_create_function16 sqlite3_api->create_function16
#define sqlite3_create_module sqlite3_api->create_module
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
#define sqlite3_data_count sqlite3_api->data_count
#define sqlite3_db_handle sqlite3_api->db_handle
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
#define sqlite3_errcode sqlite3_api->errcode
#define sqlite3_errmsg sqlite3_api->errmsg
#define sqlite3_errmsg16 sqlite3_api->errmsg16
#define sqlite3_exec sqlite3_api->exec
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_expired sqlite3_api->expired
#endif
#define sqlite3_finalize sqlite3_api->finalize
#define sqlite3_free sqlite3_api->free
#define sqlite3_free_table sqlite3_api->free_table
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_global_recover sqlite3_api->global_recover
#endif
#define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
#define sqlite3_malloc sqlite3_api->malloc
#define sqlite3_mprintf sqlite3_api->mprintf
#define sqlite3_open sqlite3_api->open
#define sqlite3_open16 sqlite3_api->open16
#define sqlite3_prepare sqlite3_api->prepare
#define sqlite3_prepare16 sqlite3_api->prepare16
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
#define sqlite3_realloc sqlite3_api->realloc
#define sqlite3_reset sqlite3_api->reset
#define sqlite3_result_blob sqlite3_api->result_blob
#define sqlite3_result_double sqlite3_api->result_double
#define sqlite3_result_error sqlite3_api->result_error
#define sqlite3_result_error16 sqlite3_api->result_error16
#define sqlite3_result_int sqlite3_api->result_int
#define sqlite3_result_int64 sqlite3_api->result_int64
#define sqlite3_result_null sqlite3_api->result_null
#define sqlite3_result_text sqlite3_api->result_text
#define sqlite3_result_text16 sqlite3_api->result_text16
#define sqlite3_result_text16be sqlite3_api->result_text16be
#define sqlite3_result_text16le sqlite3_api->result_text16le
#define sqlite3_result_value sqlite3_api->result_value
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
#define sqlite3_snprintf sqlite3_api->snprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
#define sqlite3_total_changes sqlite3_api->total_changes
#define sqlite3_trace sqlite3_api->trace
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
#endif
#define sqlite3_update_hook sqlite3_api->update_hook
#define sqlite3_user_data sqlite3_api->user_data
#define sqlite3_value_blob sqlite3_api->value_blob
#define sqlite3_value_bytes sqlite3_api->value_bytes
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
#define sqlite3_value_double sqlite3_api->value_double
#define sqlite3_value_int sqlite3_api->value_int
#define sqlite3_value_int64 sqlite3_api->value_int64
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
#define sqlite3_value_text sqlite3_api->value_text
#define sqlite3_value_text16 sqlite3_api->value_text16
#define sqlite3_value_text16be sqlite3_api->value_text16be
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
#define sqlite3_blob_close sqlite3_api->blob_close
#define sqlite3_blob_open sqlite3_api->blob_open
#define sqlite3_blob_read sqlite3_api->blob_read
#define sqlite3_blob_write sqlite3_api->blob_write
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
#define sqlite3_file_control sqlite3_api->file_control
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
#define sqlite3_memory_used sqlite3_api->memory_used
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
#define sqlite3_mutex_free sqlite3_api->mutex_free
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
#define sqlite3_mutex_try sqlite3_api->mutex_try
#define sqlite3_open_v2 sqlite3_api->open_v2
#define sqlite3_release_memory sqlite3_api->release_memory
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
#define sqlite3_sleep sqlite3_api->sleep
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
#define sqlite3_vfs_find sqlite3_api->vfs_find
#define sqlite3_vfs_register sqlite3_api->vfs_register
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
#define sqlite3_result_error_code sqlite3_api->result_error_code
#define sqlite3_test_control sqlite3_api->test_control
#define sqlite3_randomness sqlite3_api->randomness
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
#define sqlite3_limit sqlite3_api->limit
#define sqlite3_next_stmt sqlite3_api->next_stmt
#define sqlite3_sql sqlite3_api->sql
#define sqlite3_status sqlite3_api->status
#define sqlite3_backup_finish sqlite3_api->backup_finish
#define sqlite3_backup_init sqlite3_api->backup_init
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
#define sqlite3_backup_step sqlite3_api->backup_step
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
#define sqlite3_db_config sqlite3_api->db_config
#define sqlite3_db_mutex sqlite3_api->db_mutex
#define sqlite3_db_status sqlite3_api->db_status
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
#define sqlite3_log sqlite3_api->log
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
#define sqlite3_sourceid sqlite3_api->sourceid
#define sqlite3_stmt_status sqlite3_api->stmt_status
#define sqlite3_strnicmp sqlite3_api->strnicmp
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
#define sqlite3_wal_hook sqlite3_api->wal_hook
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
#define sqlite3_vtab_config sqlite3_api->vtab_config
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
/* Version 3.7.16 and later */
#define sqlite3_close_v2 sqlite3_api->close_v2
#define sqlite3_db_filename sqlite3_api->db_filename
#define sqlite3_db_readonly sqlite3_api->db_readonly
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
#define sqlite3_errstr sqlite3_api->errstr
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
#define sqlite3_stricmp sqlite3_api->stricmp
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
#define sqlite3_bind_text64 sqlite3_api->bind_text64
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
#define sqlite3_load_extension sqlite3_api->load_extension
#define sqlite3_malloc64 sqlite3_api->malloc64
#define sqlite3_msize sqlite3_api->msize
#define sqlite3_realloc64 sqlite3_api->realloc64
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
#define sqlite3_result_blob64 sqlite3_api->result_blob64
#define sqlite3_result_text64 sqlite3_api->result_text64
#define sqlite3_strglob sqlite3_api->strglob
/* Version 3.8.11 and later */
#define sqlite3_value_dup sqlite3_api->value_dup
#define sqlite3_value_free sqlite3_api->value_free
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
/* Version 3.9.0 and later */
#define sqlite3_value_subtype sqlite3_api->value_subtype
#define sqlite3_result_subtype sqlite3_api->result_subtype
/* Version 3.10.0 and later */
#define sqlite3_status64 sqlite3_api->status64
#define sqlite3_strlike sqlite3_api->strlike
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
/* Version 3.12.0 and later */
#define sqlite3_system_errno sqlite3_api->system_errno
/* Version 3.14.0 and later */
#define sqlite3_trace_v2 sqlite3_api->trace_v2
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
/* Version 3.18.0 and later */
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
/* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
# define SQLITE_EXTENSION_INIT3 \
extern const sqlite3_api_routines *sqlite3_api;
#else
/* This case when the file is being statically linked into the
** application */
# define SQLITE_EXTENSION_INIT1 /*no-op*/
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
# define SQLITE_EXTENSION_INIT3 /*no-op*/
#endif
#endif /* SQLITE3EXT_H */

View File

@ -0,0 +1,44 @@
#ifndef _SQLITE_CONFIG_RTTHREAD_H_
#define _SQLITE_CONFIG_RTTHREAD_H_
/*
* SQLite compile macro
*/
#ifndef SQLITE_MINIMUM_FILE_DESCRIPTOR
#define SQLITE_MINIMUM_FILE_DESCRIPTOR 0
#endif
#define SQLITE_OMIT_LOAD_EXTENSION 0
#define SQLITE_OMIT_WAL 1
#define SQLITE_OMIT_AUTOINIT 1
#ifndef SQLITE_RTTHREAD_NO_WIDE
#define SQLITE_RTTHREAD_NO_WIDE 1
#endif
#ifndef SQLITE_TEMP_STORE
#define SQLITE_TEMP_STORE 1
#endif
#ifndef SQLITE_THREADSAFE
#define SQLITE_THREADSAFE 1
#endif
#ifndef HAVE_READLINE
#define HAVE_READLINE 0
#endif
#ifndef NDEBUG
#define NDEBUG
#endif
#ifndef SQLITE_OS_OTHER
#define SQLITE_OS_OTHER 1
#endif
#ifndef SQLITE_OS_RTTHREAD
#define SQLITE_OS_RTTHREAD 1
#endif
#endif

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file sqlite_config_xiuos.h
* @brief support SQLite define for XiUOS, include rtthread and xizi kernel
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-16
*/
/*************************************************
File name: sqlite_config_xiuos.h
Description: support SQLite define for XiUOS, include rtthread and xizi kernel
Others:
History:
1. Date: 2023-10-16
Author: AIIT XUOS Lab
Modification:
1modify ifndef description
*************************************************/
#ifndef _SQLITE_CONFIG_XIUOS_H_
#define _SQLITE_CONFIG_XIUOS_H_
#include <transform.h>
/*
* SQLite compile macro
*/
#ifndef SQLITE_MINIMUM_FILE_DESCRIPTOR
#define SQLITE_MINIMUM_FILE_DESCRIPTOR 0
#endif
#define SQLITE_OMIT_LOAD_EXTENSION 0
#define SQLITE_OMIT_WAL 1
#define SQLITE_OMIT_AUTOINIT 1
#ifndef SQLITE_RTTHREAD_NO_WIDE
#define SQLITE_RTTHREAD_NO_WIDE 1
#endif
#ifndef SQLITE_TEMP_STORE
#define SQLITE_TEMP_STORE 1
#endif
#ifndef SQLITE_THREADSAFE
#define SQLITE_THREADSAFE 1
#endif
#ifndef HAVE_READLINE
#define HAVE_READLINE 0
#endif
#ifndef NDEBUG
#define NDEBUG
#endif
#ifndef SQLITE_OS_OTHER
#define SQLITE_OS_OTHER 1
#endif
#ifndef SQLITE_OS_XIUOS
#define SQLITE_OS_XIUOS 1
#endif
#ifndef PKG_SQLITE_SQL_MAX_LEN
#define PKG_SQLITE_SQL_MAX_LEN LIB_SQLITE_SQL_MAX_LEN
#endif
#ifndef PKG_SQLITE_DB_NAME_MAX_LEN
#define PKG_SQLITE_DB_NAME_MAX_LEN LIB_SQLITE_DB_NAME_MAX_LEN
#endif
#ifndef SQLITE_ASSERT
#define SQLITE_ASSERT(EXPR) \
if (!(EXPR)) \
{ \
printf("(%s) has CHECK failed at %s.", #EXPR, __FUNCTION__); \
while (1); \
}
#endif
#endif

View File

@ -0,0 +1,744 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-10 lizhen9880 first version
*/
/**
* @file student_dao.c
* @brief support SQLite demo using dbhelper api in XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-25
*/
/*************************************************
File name: student_dao.c
Description: support SQLite demo using dbhelper api in XiUOS
Others:
History:
1. Date: 2023-10-25
Author: AIIT XUOS Lab
Modification:
1add XiUOS function.
*************************************************/
#include <transform.h>
#ifdef ADD_RTTHREAD_FEATURES
#include <rtthread.h>
#include <dfs_posix.h>
#endif
#ifdef ADD_XIZI_FEATURES
#include <list.h>
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"
#include "dbhelper.h"
#include "student_dao.h"
#define DBG_ENABLE
#define DBG_SECTION_NAME "app.student_dao"
#define DBG_LEVEL DBG_INFO
#define DBG_COLOR
#ifdef ADD_RTTHREAD_FEATURES
#include <rtdbg.h>
static int student_insert_bind(sqlite3_stmt *stmt, int index, void *arg)
{
int rc;
rt_list_t *h = arg, *pos, *n;
student_t *s = RT_NULL;
rt_list_for_each_safe(pos, n, h)
{
s = rt_list_entry(pos, student_t, list);
sqlite3_reset(stmt); //reset the stmt
sqlite3_bind_text(stmt, 1, s->name, strlen(s->name), NULL); //bind the 1st data,is a string
sqlite3_bind_int(stmt, 2, s->score); //bind the 1st data,is a int
rc = sqlite3_step(stmt); //execute the stmt by step
}
if (rc != SQLITE_DONE)
return rc;
return SQLITE_OK;
}
int student_add(rt_list_t *h)
{
return db_nonquery_operator("insert into student(name,score) values (?,?);", student_insert_bind, h);
}
int student_del(int id)
{
return db_nonquery_by_varpara("delete from student where id=?;", "%d", id);
}
int student_del_all(void)
{
return db_nonquery_operator("delete from student;", 0, 0);
}
static int student_update_bind(sqlite3_stmt *stmt, int index, void *arg)
{
int rc;
student_t *s = arg;
sqlite3_bind_text(stmt, 1, s->name, strlen(s->name), NULL);
sqlite3_bind_int(stmt, 2, s->score);
sqlite3_bind_int(stmt, 3, s->id);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE)
return rc;
return SQLITE_OK;
}
int student_update(student_t *s)
{
return db_nonquery_operator("update student set name=?,score=? where id=?;", student_update_bind, s);
}
static int student_create(sqlite3_stmt *stmt, void *arg)
{
student_t *s = arg;
int ret = sqlite3_step(stmt);
if (ret != SQLITE_ROW)
{
return 0;
}
else
{
s->id = db_stmt_get_int(stmt, 0);
db_stmt_get_text(stmt, 1, s->name);
s->score = db_stmt_get_int(stmt, 2);
}
return ret;
}
int student_get_by_id(student_t *s, int id)
{
int res = db_query_by_varpara("select * from student where id=?;", student_create, s, "%d", id);
return res;
}
void student_free_list(rt_list_t *h)
{
rt_list_t *head = h, *pos, *n;
student_t *p = RT_NULL;
rt_list_for_each_safe(pos, n, head)
{
p = rt_list_entry(pos, student_t, list);
rt_free(p);
}
rt_free(head);
}
void student_print_list(rt_list_t *q)
{
student_t *s = NULL;
for (s = rt_list_entry((q)->next, student_t, list);
&s->list != (q);
s = rt_list_entry(s->list.next, student_t, list))
{
rt_kprintf("id:%d\tname:%s\tscore:%d\n", s->id, s->name, s->score);
}
}
static int student_create_queue(sqlite3_stmt *stmt, void *arg)
{
rt_list_t *q = arg;
student_t *s;
int ret, count = 0;
ret = sqlite3_step(stmt);
if (ret != SQLITE_ROW)
{
return 0;
}
do
{
s = rt_calloc(sizeof(student_t), 1);
if (!s)
{
LOG_E("No enough memory!");
goto __create_student_fail;
}
s->id = db_stmt_get_int(stmt, 0);
db_stmt_get_text(stmt, 1, s->name);
s->score = db_stmt_get_int(stmt, 2);
rt_list_insert_before(q, &(s->list));
count++;
} while ((ret = sqlite3_step(stmt)) == SQLITE_ROW);
return count;
__create_student_fail:
return -1;
}
int student_get_all(rt_list_t *q)
{
return db_query_by_varpara("select * from student;", student_create_queue, q, RT_NULL);
}
static void list_all(void)
{
rt_kprintf("test get all students\n");
rt_list_t *h = rt_calloc(sizeof(student_t), 1);
rt_list_init(h);
int ret = student_get_all(h);
if (ret >= 0)
{
student_print_list(h);
rt_kprintf("record(s):%d\n", ret);
}
else
{
rt_kprintf("Get students information failed");
}
student_free_list(h);
return;
}
int student_get_by_score(rt_list_t *h, int ls, int hs, enum order_type order)
{
char sql[128];
rt_snprintf(sql, 128, "select * from student where score between %d and %d ORDER BY score %s;", ls, hs, order == ASC ? "ASC" : "DESC");
return db_query_by_varpara(sql, student_create_queue, h, RT_NULL);
}
static void list_by_score(int ls, int hs, enum order_type order)
{
rt_list_t *h = rt_calloc(sizeof(rt_list_t), 1);
rt_list_init(h);
rt_kprintf("the student list of score between %d and %d:\n", ls, hs);
int ret = student_get_by_score(h, ls, hs, order);
if (ret >= 0)
{
student_print_list(h);
rt_kprintf("record(s):%d\n", ret);
}
else
{
LOG_E("Get students information failed!");
}
student_free_list(h);
return;
}
static void stu(uint8_t argc, char **argv)
{
if (argc < 2)
{
list_all();
return;
}
else
{
char *cmd = argv[1];
int rand = 0;
if (rt_strcmp(cmd, "add") == 0)
{
int i = 0, count = 0;
if (argc >= 3)
{
count = atol(argv[2]);
}
if (count == 0)
{
count = 1;
}
rt_tick_t ticks = rt_tick_get();
rand = ticks;
rt_list_t *h = (rt_list_t *)rt_calloc(1, sizeof(rt_list_t));
rt_list_init(h);
for (i = 0; i < count; i++)
{
student_t *s = (student_t *)rt_calloc(1, sizeof(student_t));
rand += i;
rand %= 99999;
s->score = (rand % 81) + 20;
sprintf(s->name, "Student%d", rand);
rt_list_insert_before(h, &(s->list));
}
int res = student_add(h);
student_free_list(h);
if (res != SQLITE_OK)
{
LOG_E("add failed!");
}
else
{
ticks = rt_tick_get() - ticks;
rt_kprintf("Insert %d record(s): %dms, speed: %dms/record\n", count,
ticks * 1000 / RT_TICK_PER_SECOND, ticks * 1000 / RT_TICK_PER_SECOND / count);
}
}
else if (rt_strcmp(cmd, "del") == 0)
{
if (argc == 2)
{
if (student_del_all() == SQLITE_OK)
{
rt_kprintf("Del all record success!\n");
}
else
{
rt_kprintf("Del all record failed!\n");
}
}
else
{
rt_uint32_t id = atol(argv[2]);
if (student_del(id) == SQLITE_OK)
{
rt_kprintf("Del record success with id:%d\n", id);
}
else
{
rt_kprintf("Del record failed with id:%d\n", id);
}
}
}
else if (rt_strcmp(cmd, "update") == 0)
{
/* update student record by id */
if (argc >= 5)
{
student_t *s = rt_calloc(sizeof(student_t), 1);
s->id = atol(argv[2]);
rt_strncpy(s->name, argv[3], rt_strlen(argv[3]));
s->score = atol(argv[4]);
if (student_update(s) == SQLITE_OK)
{
rt_kprintf("update record success!\n");
}
else
{
rt_kprintf("update record failed!\n");
}
rt_free(s);
}
else
{
rt_kprintf("usage: stu update id name score\n");
}
}
else if (rt_strcmp(cmd, "score") == 0)
{
/* query student's score between LOW and HIGH. */
if (argc >= 4)
{
enum order_type order = ASC;
int ls = atol(argv[2]);
int hs = atol(argv[3]);
if (rt_strcmp(argv[4], "-d") == 0)
{
order = DESC;
}
list_by_score(ls, hs, order);
}
else
{
rt_kprintf("usage: stu score LOW HIGH [OPTION]\n"
"desc:query student's score between LOW and HIGH.\n"
"OPTION(default ascending):\n -a:ascending\n -d:descending\n"
"e.g: stu score 60 100 or stu score -d 60 100\n");
}
}
else
{
student_t *s = rt_calloc(sizeof(student_t), 1);
rt_uint32_t id = atol(argv[1]);
if (student_get_by_id(s, id) > 0)
{
rt_kprintf("id:%d\t\tname:%s\tscore:%d\n", s->id, s->name, s->score);
}
else
{
rt_kprintf("no record with id:%d\n", id);
}
rt_free(s);
}
}
}
MSH_CMD_EXPORT(stu, student add del update query);
static int create_student_tbl(void)
{
int fd = 0;
db_set_name("/stu_info.db");
fd = open(db_get_name(), O_RDONLY);
rt_kprintf(db_get_name());
if (fd < 0)
{
/* there is not the .db file.create db and table */
const char *sql = "CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(32) NOT NULL,score INT NOT NULL);";
return db_create_database(sql);
}
else if (db_table_is_exist("student") > 0)
{
/* there is the table int db.close the db. */
close(fd);
LOG_I("The table has already existed!\n");
return RT_EOK;
}
else
{
/* there is not the table int db.create the table */
const char *sql = "CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(32) NOT NULL,score INT NOT NULL);";
return db_create_database(sql);
}
}
MSH_CMD_EXPORT(create_student_tbl, create sqlite db);
#endif
static int student_insert_bind(sqlite3_stmt *stmt, int index, void *arg)
{
int rc = 0;
DoublelistType *h = arg, *node, *node_next;
student_t *s = NULL;
DOUBLE_LIST_FOR_EACH_SAFE(node, node_next, h)
{
s = DOUBLE_LIST_ENTRY(node, student_t, list);
sqlite3_reset(stmt); //reset the stmt
sqlite3_bind_text(stmt, 1, s->name, strlen(s->name), NULL); //bind the 1st data,is a string
sqlite3_bind_int(stmt, 2, s->score); //bind the 1st data,is a int
rc = sqlite3_step(stmt); //execute the stmt by step
}
if (rc != SQLITE_DONE)
return rc;
return SQLITE_OK;
}
int student_add(DoublelistType *h)
{
return db_nonquery_operator("insert into student(name,score) values (?,?);", student_insert_bind, h);
}
int student_del(int id)
{
return db_nonquery_by_varpara("delete from student where id=?;", "%d", id);
}
int student_del_all(void)
{
return db_nonquery_operator("delete from student;", 0, 0);
}
static int student_update_bind(sqlite3_stmt *stmt, int index, void *arg)
{
int rc;
student_t *s = arg;
sqlite3_bind_text(stmt, 1, s->name, strlen(s->name), NULL);
sqlite3_bind_int(stmt, 2, s->score);
sqlite3_bind_int(stmt, 3, s->id);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE)
return rc;
return SQLITE_OK;
}
int student_update(student_t *s)
{
return db_nonquery_operator("update student set name=?,score=? where id=?;", student_update_bind, s);
}
static int student_create(sqlite3_stmt *stmt, void *arg)
{
student_t *s = arg;
int ret = sqlite3_step(stmt);
if (ret != SQLITE_ROW)
{
return 0;
}
else
{
s->id = db_stmt_get_int(stmt, 0);
db_stmt_get_text(stmt, 1, s->name);
s->score = db_stmt_get_int(stmt, 2);
}
return ret;
}
int student_get_by_id(student_t *s, int id)
{
int res = db_query_by_varpara("select * from student where id=?;", student_create, s, "%d", id);
return res;
}
void student_free_list(DoublelistType *h)
{
DoublelistType *head = h, *node, *node_next;
student_t *p = NULL;
DOUBLE_LIST_FOR_EACH_SAFE(node, node_next, head)
{
p = DOUBLE_LIST_ENTRY(node, student_t, list);
PrivFree(p);
}
PrivFree(head);
}
void student_print_list(DoublelistType *q)
{
student_t *s = NULL;
for (s = DOUBLE_LIST_ENTRY((q)->node_next, student_t, list);
&s->list != (q);
s = DOUBLE_LIST_ENTRY(s->list.node_next, student_t, list))
{
printf("id:%d\tname:%s\tscore:%d\n", s->id, s->name, s->score);
}
}
static int student_create_queue(sqlite3_stmt *stmt, void *arg)
{
DoublelistType *q = arg;
student_t *s;
int ret, count = 0;
ret = sqlite3_step(stmt);
if (ret != SQLITE_ROW)
{
return 0;
}
do
{
s = PrivCalloc(1, sizeof(student_t));
if (!s)
{
printf("No enough memory!");
goto __create_student_fail;
}
s->id = db_stmt_get_int(stmt, 0);
db_stmt_get_text(stmt, 1, s->name);
s->score = db_stmt_get_int(stmt, 2);
AppDoubleListInsertNodeBefore(q, &(s->list));
count++;
} while ((ret = sqlite3_step(stmt)) == SQLITE_ROW);
return count;
__create_student_fail:
return -1;
}
int student_get_all(DoublelistType *q)
{
return db_query_by_varpara("select * from student;", student_create_queue, q, NULL);
}
static void list_all(void)
{
printf("test get all students\n");
DoublelistType *h = PrivCalloc(1, sizeof(student_t));
AppInitDoubleList(h);
int ret = student_get_all(h);
if (ret >= 0)
{
student_print_list(h);
printf("record(s):%d\n", ret);
}
else
{
printf("Get students information failed");
}
student_free_list(h);
return;
}
int student_get_by_score(DoublelistType *h, int ls, int hs, enum order_type order)
{
char sql[128];
snprintf(sql, 128, "select * from student where score between %d and %d ORDER BY score %s;", ls, hs, order == ASC ? "ASC" : "DESC");
return db_query_by_varpara(sql, student_create_queue, h, NULL);
}
static void list_by_score(int ls, int hs, enum order_type order)
{
DoublelistType *h = PrivCalloc(1, sizeof(DoublelistType));
AppInitDoubleList(h);
printf("the student list of score between %d and %d:\n", ls, hs);
int ret = student_get_by_score(h, ls, hs, order);
if (ret >= 0)
{
student_print_list(h);
printf("record(s):%d\n", ret);
}
else
{
printf("Get students information failed!");
}
student_free_list(h);
return;
}
static int stu(int argc, char *argv[])
{
if (argc < 2)
{
list_all();
}
else
{
char *cmd = argv[1];
int rand = 0;
if (strcmp(cmd, "add") == 0)
{
int i = 0, count = 0;
if (argc >= 3)
{
count = atol(argv[2]);
}
if (count == 0)
{
count = 1;
}
int start_time = PrivGetTickTime();
rand = start_time;
DoublelistType *h = (DoublelistType *)PrivCalloc(1, sizeof(DoublelistType));
AppInitDoubleList(h);
for (i = 0; i < count; i++)
{
student_t *s = (student_t *)PrivCalloc(1, sizeof(student_t));
rand += i;
rand %= 99999;
s->score = (rand % 81) + 20;
sprintf(s->name, "Student%d", rand);
AppDoubleListInsertNodeBefore(h, &(s->list));
}
int res = student_add(h);
student_free_list(h);
if (res != SQLITE_OK)
{
printf("add failed!");
}
else
{
int end_time = PrivGetTickTime() - start_time;
printf("Insert %d record(s): %dms, speed: %dms/record\n", count,
end_time, end_time / count);
}
}
else if (strcmp(cmd, "del") == 0)
{
if (argc == 2)
{
if (student_del_all() == SQLITE_OK)
{
printf("Del all record success!\n");
}
else
{
printf("Del all record failed!\n");
}
}
else
{
uint32_t id = atol(argv[2]);
if (student_del(id) == SQLITE_OK)
{
printf("Del record success with id:%d\n", id);
}
else
{
printf("Del record failed with id:%d\n", id);
}
}
}
else if (strcmp(cmd, "update") == 0)
{
/* update student record by id */
if (argc >= 5)
{
student_t *s = PrivCalloc(sizeof(student_t), 1);
s->id = atol(argv[2]);
strncpy(s->name, argv[3], strlen(argv[3]));
s->score = atol(argv[4]);
if (student_update(s) == SQLITE_OK)
{
printf("update record success!\n");
}
else
{
printf("update record failed!\n");
}
PrivFree(s);
}
else
{
printf("usage: stu update id name score\n");
}
}
else if (strcmp(cmd, "score") == 0)
{
/* query student's score between LOW and HIGH. */
if (argc >= 4)
{
enum order_type order = ASC;
int ls = atol(argv[2]);
int hs = atol(argv[3]);
if (strcmp(argv[4], "-d") == 0)
{
order = DESC;
}
list_by_score(ls, hs, order);
}
else
{
printf("usage: stu score LOW HIGH [OPTION]\n"
"desc:query student's score between LOW and HIGH.\n"
"OPTION(default ascending):\n -a:ascending\n -d:descending\n"
"e.g: stu score 60 100 or stu score -d 60 100\n");
}
}
else
{
student_t *s = PrivCalloc(sizeof(student_t), 1);
uint32_t id = atol(argv[1]);
if (student_get_by_id(s, id) > 0)
{
printf("id:%d\t\tname:%s\tscore:%d\n", s->id, s->name, s->score);
}
else
{
printf("no record with id:%d\n", id);
}
PrivFree(s);
}
}
return 0;
}
PRIV_SHELL_CMD_FUNCTION(stu, student add del update query, PRIV_SHELL_CMD_MAIN_ATTR);
static int create_student_tbl(void)
{
int fd = -1;
//init sqlite3
db_helper_init();
db_set_name("/stu_info.db");
fd = PrivOpen("/stu_info.db", O_RDONLY);
printf(db_get_name());
printf(" fd %d\n", fd);
if (fd < 0)
{
/* there is not the .db file.create db and table */
const char *sql = "CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(32) NOT NULL,score INT NOT NULL);";
return db_create_database(sql);
}
else if (db_table_is_exist("student") > 0)
{
/* there is the table int db.close the db. */
PrivClose(fd);
printf("The table has already existed!\n");
return 0;
}
else
{
/* there is not the table int db.create the table */
const char *sql = "CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(32) NOT NULL,score INT NOT NULL);";
return db_create_database(sql);
}
}
PRIV_SHELL_CMD_FUNCTION(create_student_tbl, create sqlite db, PRIV_SHELL_CMD_FUNC_ATTR);

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-10 lizhen9880 first version
*/
#ifndef __STUDENT_DAO_H__
#define __STUDENT_DAO_H__
#ifdef ADD_RTTHREAD_FEATURES
#include <rtthread.h>
#endif
struct student
{
unsigned int id;
char name[32];
int score;
#ifdef ADD_RTTHREAD_FEATURES
rt_list_t list;
#endif
#ifdef ADD_XIZI_FEATURES
DoublelistType list;
#endif
};
typedef struct student student_t;
/**
* ASC:Ascending
* DESC:Descending
* */
enum order_type
{
ASC = 0,
DESC = 1,
};
#ifdef ADD_RTTHREAD_FEATURES
int student_get_by_id(student_t *e, int id);
int student_get_by_score(rt_list_t *h, int ls, int hs, enum order_type order);
int student_get_all(rt_list_t *q);
int student_add(rt_list_t *h);
int student_del(int id);
int student_del_all(void);
int student_update(student_t *e);
void student_free_list(rt_list_t *h);
void student_print_list(rt_list_t *q);
#endif
#ifdef ADD_XIZI_FEATURES
int student_get_by_id(student_t *e, int id);
int student_get_by_score(DoublelistType *h, int ls, int hs, enum order_type order);
int student_get_all(DoublelistType *q);
int student_add(DoublelistType *h);
int student_del(int id);
int student_del_all(void);
int student_update(student_t *e);
void student_free_list(DoublelistType *h);
void student_print_list(DoublelistType *q);
#endif
#endif

View File

@ -0,0 +1,4 @@
SRC_FILES := xizi_io_methods.c xizi_mutex.c xizi_vfs.c
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,469 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file xizi_io_methods.c
* @brief support SQLite io function in XiZi kernel
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-16
*/
/*************************************************
File name: xizi_io_methods.c
Description: support SQLite io function in XiZi kernel
Others:
History:
1. Date: 2023-10-16
Author: AIIT XUOS Lab
Modification:
1add xizi vfs io function.
*************************************************/
#include "xizi_port.h"
static int _xizi_io_read(sqlite3_file *file_id, void *pbuf, int cnt, sqlite3_int64 offset)
{
XIZI_SQLITE_FILE_T *file = (XIZI_SQLITE_FILE_T*)file_id;
sqlite3_int64 new_offset;
int r_cnt;
SQLITE_ASSERT(file_id);
SQLITE_ASSERT(offset >= 0);
SQLITE_ASSERT(cnt > 0);
new_offset = PrivLseek(file->fd, offset, SEEK_SET);
if (new_offset != offset) {
return SQLITE_IOERR_READ;
}
do {
r_cnt = PrivRead(file->fd, pbuf, cnt);
if (r_cnt == cnt) {
break;
}
if (r_cnt < 0) {
if (errno != EINTR) {
return SQLITE_IOERR_READ;
}
r_cnt = 1;
continue;
} else if (r_cnt > 0) {
cnt -= r_cnt;
pbuf = (void*)(r_cnt + (char*)pbuf);
}
} while (r_cnt > 0);
if (r_cnt != cnt) {
memset(&((char*)pbuf)[r_cnt], 0, cnt - r_cnt);
return SQLITE_IOERR_SHORT_READ;
}
return SQLITE_OK;
}
static int _xizi_io_write(sqlite3_file* file_id, const void *pbuf, int cnt, sqlite3_int64 offset)
{
XIZI_SQLITE_FILE_T *file = (XIZI_SQLITE_FILE_T*)file_id;
sqlite3_int64 new_offset;
int w_cnt;
SQLITE_ASSERT(file_id);
SQLITE_ASSERT(cnt > 0);
new_offset = PrivLseek(file->fd, offset, SEEK_SET);
if (new_offset != offset) {
return SQLITE_IOERR_WRITE;
}
do {
w_cnt = PrivWrite(file->fd, pbuf, cnt);
if (w_cnt == cnt) {
break;
}
if (w_cnt < 0) {
if (errno != EINTR) {
return SQLITE_IOERR_WRITE;
}
w_cnt = 1;
continue;
} else if (w_cnt > 0) {
cnt -= w_cnt;
pbuf = (void*)(w_cnt + (char*)pbuf);
}
} while (w_cnt > 0);
if (w_cnt != cnt) {
return SQLITE_FULL;
}
return SQLITE_OK;
}
static int _xizi_io_truncate(sqlite3_file* file_id, sqlite3_int64 size)
{
return SQLITE_IOERR_TRUNCATE;
}
static int _xizi_io_sync(sqlite3_file* file_id, int flags)
{
XIZI_SQLITE_FILE_T *file = (XIZI_SQLITE_FILE_T*)file_id;
SQLITE_ASSERT((flags & 0x0F) == SQLITE_SYNC_NORMAL
|| (flags & 0x0F) == SQLITE_SYNC_FULL);
PrivFsync(file->fd);
return SQLITE_OK;
}
static int _xizi_io_file_size(sqlite3_file* file_id, sqlite3_int64 *psize)
{
int rc;
struct stat buf;
XIZI_SQLITE_FILE_T *file = (XIZI_SQLITE_FILE_T*)file_id;
SQLITE_ASSERT(file_id);
rc = PrivFstat(file->fd, &buf);
if (rc != 0) {
return SQLITE_IOERR_FSTAT;
}
*psize = buf.st_size;
/* When opening a zero-size database, the findInodeInfo() procedure
** writes a single byte into that file in order to work around a bug
** in the OS-X msdos filesystem. In order to avoid problems with upper
** layers, we need to report this file size as zero even though it is
** really 1. Ticket #3260.
*/
if (*psize == 1) *psize = 0;
return SQLITE_OK;
}
/*
** This routine checks if there is a RESERVED lock held on the specified
** file by this or any other process. If such a lock is held, set *pResOut
** to a non-zero value otherwise *pResOut is set to zero. The return value
** is set to SQLITE_OK unless an I/O error occurs during lock checking.
*/
static int _xizi_io_check_reserved_lock(sqlite3_file *file_id, int *pResOut)
{
XIZI_SQLITE_FILE_T *file = (XIZI_SQLITE_FILE_T*)file_id;
sem_t psem = file->sem;
int reserved = 0;
/* Check if a thread in this process holds such a lock */
if (file->eFileLock > 1) {
reserved = 1;
}
/* Otherwise see if some other process holds it. */
if (!reserved) {
if (PrivSemaphoreObtainNoWait(&psem) != 0) {
/* someone else has the lock when we are in NO_LOCK */
reserved = (file->eFileLock < 1);
} else {
/* we could have it if we want it */
PrivSemaphoreAbandon(&psem);
}
}
*pResOut = reserved;
return SQLITE_OK;
}
/*
** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
** (2) RESERVED_LOCK
** (3) PENDING_LOCK
** (4) EXCLUSIVE_LOCK
**
** Sometimes when requesting one lock state, additional lock states
** are inserted in between. The locking might fail on one of the later
** transitions leaving the lock state different from what it started but
** still short of its goal. The following chart shows the allowed
** transitions and the inserted intermediate states:
**
** UNLOCKED -> SHARED
** SHARED -> RESERVED
** SHARED -> (PENDING) -> EXCLUSIVE
** RESERVED -> (PENDING) -> EXCLUSIVE
** PENDING -> EXCLUSIVE
**
** Semaphore locks only really support EXCLUSIVE locks. We track intermediate
** lock states in the sqlite3_file structure, but all locks SHARED or
** above are really EXCLUSIVE locks and exclude all other processes from
** access the file.
**
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
static int _xizi_io_lock(sqlite3_file *file_id, int eFileLock)
{
XIZI_SQLITE_FILE_T *file = (XIZI_SQLITE_FILE_T*)file_id;
sem_t psem = file->sem;
int rc = SQLITE_OK;
/* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
if (file->eFileLock > 0) {
file->eFileLock = eFileLock;
rc = SQLITE_OK;
goto sem_end_lock;
}
/* lock semaphore now but bail out when already locked. */
if (PrivSemaphoreObtainNoWait(&psem) != 0) {
rc = SQLITE_BUSY;
goto sem_end_lock;
}
/* got it, set the type and return ok */
file->eFileLock = eFileLock;
sem_end_lock:
return rc;
}
/*
** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
static int _xizi_io_unlock(sqlite3_file *file_id, int eFileLock)
{
XIZI_SQLITE_FILE_T *file = (XIZI_SQLITE_FILE_T*)file_id;
sem_t psem = file->sem;
SQLITE_ASSERT(eFileLock <= 1);
/* no-op if possible */
if (file->eFileLock == eFileLock) {
return SQLITE_OK;
}
/* shared can just be set because we always have an exclusive */
if (eFileLock == 1) {
file->eFileLock = 1;
return SQLITE_OK;
}
/* no, really unlock. */
PrivSemaphoreAbandon(&psem);
file->eFileLock = 0;
return SQLITE_OK;
}
static int _xizi_io_close(sqlite3_file *file_id)
{
int rc = 0;
XIZI_SQLITE_FILE_T *file = (XIZI_SQLITE_FILE_T*)file_id;
if (file->fd >= 0) {
_xizi_io_unlock(file_id, 0);
PrivSemaphoreDelete(&file->sem);
rc = PrivClose(file->fd);
file->fd = -1;
}
return rc;
}
static int _xizi_fcntl_size_hint(sqlite3_file *file_id, sqlite3_int64 nByte)
{
XIZI_SQLITE_FILE_T *file = (XIZI_SQLITE_FILE_T*)file_id;
if (file->szChunk > 0) {
sqlite3_int64 nSize; /* Required file size */
struct stat buf; /* Used to hold return values of fstat() */
if (PrivFstat(file->fd, &buf)) {
return SQLITE_IOERR_FSTAT;
}
nSize = ((nByte + file->szChunk - 1) / file->szChunk) * file->szChunk;
if (nSize > (sqlite3_int64)buf.st_size) {
/* If the OS does not have posix_fallocate(), fake it. Write a
** single byte to the last byte in each block that falls entirely
** within the extended region. Then, if required, a single byte
** at offset (nSize-1), to set the size of the file correctly.
** This is a similar technique to that used by glibc on systems
** that do not have a real fallocate() call.
*/
int nBlk = 512; /* File-system block size */
int nWrite = 0; /* Number of bytes written by seekAndWrite */
sqlite3_int64 iWrite; /* Next offset to write to */
iWrite = (buf.st_size / nBlk) * nBlk + nBlk - 1;
SQLITE_ASSERT(iWrite >= buf.st_size);
SQLITE_ASSERT(((iWrite + 1) % nBlk) == 0);
for (/*no-op*/; iWrite < nSize + nBlk - 1; iWrite += nBlk) {
if (iWrite >= nSize) {
iWrite = nSize - 1;
}
nWrite = _xizi_io_write(file_id, "", 1, iWrite);
if (nWrite != 1) {
return SQLITE_IOERR_WRITE;
}
}
}
}
return SQLITE_OK;
}
/*
** Information and control of an open file handle.
*/
static int _xizi_io_file_ctrl(sqlite3_file *file_id, int op, void *pArg)
{
XIZI_SQLITE_FILE_T *file = (XIZI_SQLITE_FILE_T*)file_id;
switch( op ) {
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = file->eFileLock;
return SQLITE_OK;
}
case SQLITE_LAST_ERRNO: {
*(int*)pArg = 0;
return SQLITE_OK;
}
case SQLITE_FCNTL_CHUNK_SIZE: {
file->szChunk = *(int *)pArg;
return SQLITE_OK;
}
case SQLITE_FCNTL_SIZE_HINT: {
int rc;
rc = _xizi_fcntl_size_hint(file_id, *(sqlite3_int64 *)pArg);
return rc;
}
case SQLITE_FCNTL_PERSIST_WAL: {
return SQLITE_OK;
}
case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
return SQLITE_OK;
}
case SQLITE_FCNTL_VFSNAME: {
*(char**)pArg = sqlite3_mprintf("%s", file->pvfs->zName);
return SQLITE_OK;
}
case SQLITE_FCNTL_TEMPFILENAME: {
char *zTFile = sqlite3_malloc(file->pvfs->mxPathname );
if( zTFile ) {
_xizi_get_temp_name(file->pvfs->mxPathname, zTFile);
*(char**)pArg = zTFile;
}
return SQLITE_OK;
}
}
return SQLITE_NOTFOUND;
}
// #ifndef SQLITE_DEFAULT_SECTOR_SIZE
// # define SQLITE_DEFAULT_SECTOR_SIZE 4096
// #endif
static int _xizi_io_sector_size(sqlite3_file *file_id)
{
return 4096;
}
static int _xizi_io_device_characteristics(sqlite3_file *file_id)
{
return SQLITE_IOCAP_SAFE_APPEND;
}
/*
** If possible, return a pointer to a mapping of file fd starting at offset
** iOff. The mapping must be valid for at least nAmt bytes.
**
** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
** Finally, if an error does occur, return an SQLite error code. The final
** value of *pp is undefined in this case.
**
** If this function does return a pointer, the caller must eventually
** release the reference by calling unixUnfetch().
*/
static int _xizi_io_fetch(sqlite3_file *file_id, sqlite3_int64 iOff, int nAmt, void **pp)
{
*pp = 0;
return SQLITE_OK;
}
/*
** If the third argument is non-NULL, then this function releases a
** reference obtained by an earlier call to unixFetch(). The second
** argument passed to this function must be the same as the corresponding
** argument that was passed to the unixFetch() invocation.
**
** Or, if the third argument is NULL, then this function is being called
** to inform the VFS layer that, according to POSIX, any existing mapping
** may now be invalid and should be unmapped.
*/
static int _xizi_io_unfetch(sqlite3_file *fd, sqlite3_int64 iOff, void *p)
{
return SQLITE_OK;
}
static const sqlite3_io_methods _xizi_io_method = {
3,
_xizi_io_close,
_xizi_io_read,
_xizi_io_write,
_xizi_io_truncate,
_xizi_io_sync,
_xizi_io_file_size,
_xizi_io_lock,
_xizi_io_unlock,
_xizi_io_check_reserved_lock,
_xizi_io_file_ctrl,
_xizi_io_sector_size,
_xizi_io_device_characteristics,
0,
0,
0,
0,
_xizi_io_fetch,
_xizi_io_unfetch
};

View File

@ -0,0 +1,202 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file xizi_mutex.c
* @brief support SQLite mutex function in XiZi kernel
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-16
*/
/*************************************************
File name: xizi_mutex.c
Description: support SQLite mutex function in XiZi kernel
Others:
History:
1. Date: 2023-10-16
Author: AIIT XUOS Lab
Modification:
1add xizi mutex function.
*************************************************/
#include "xizi_port.h"
struct sqlite3_mutex {
pthread_mutex_t mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
};
static void sqlite3MemoryBarrier(void)
{
}
/*
** Initialize and deinitialize the mutex subsystem.
The argument to sqlite3_mutex_alloc() must one of these integer constants:
SQLITE_MUTEX_FAST
SQLITE_MUTEX_RECURSIVE
SQLITE_MUTEX_STATIC_MASTER
SQLITE_MUTEX_STATIC_MEM
SQLITE_MUTEX_STATIC_OPEN
SQLITE_MUTEX_STATIC_PRNG
SQLITE_MUTEX_STATIC_LRU
SQLITE_MUTEX_STATIC_PMEM
SQLITE_MUTEX_STATIC_APP1
SQLITE_MUTEX_STATIC_APP2
SQLITE_MUTEX_STATIC_APP3
SQLITE_MUTEX_STATIC_VFS1
SQLITE_MUTEX_STATIC_VFS2
SQLITE_MUTEX_STATIC_VFS3
The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
cause sqlite3_mutex_alloc() to create a new mutex. The new mutex is recursive
when SQLITE_MUTEX_RECURSIVE is used but not necessarily so when SQLITE_MUTEX_FAST
is used. The mutex implementation does not need to make a distinction between
SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does not want to.
SQLite will only request a recursive mutex in cases where it really needs one.
If a faster non-recursive mutex implementation is available on the host platform,
the mutex subsystem might return such a mutex in response to SQLITE_MUTEX_FAST.
The other allowed parameters to sqlite3_mutex_alloc()
(anything other than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return
a pointer to a static preexisting mutex. Nine static mutexes are used by the
current version of SQLite. Future versions of SQLite may add additional static
mutexes. Static mutexes are for internal use by SQLite only. Applications that
use SQLite mutexes should use only the dynamic mutexes returned by SQLITE_MUTEX_FAST
or SQLITE_MUTEX_RECURSIVE.
Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST or SQLITE_MUTEX_RECURSIVE)
is used then sqlite3_mutex_alloc() returns a different mutex on every call.
For the static mutex types, the same mutex is returned on every call that has the same type number.
*/
static sqlite3_mutex _static_mutex[12];
static int _xizi_mtx_init(void)
{
int i;
int err;
for (i = 0; i < sizeof(_static_mutex) / sizeof(_static_mutex[0]); i++) {
err = PrivMutexCreate(&_static_mutex[i].mutex, 0);
if (err != 0) {
return SQLITE_ERROR;
}
}
return SQLITE_OK;
}
static int _xizi_mtx_end(void)
{
int i;
int err;
for (i = 0; i < sizeof(_static_mutex) / sizeof(_static_mutex[0]); i++)
{
err = PrivMutexDelete(&_static_mutex[i].mutex);
if (err != 0) {
return SQLITE_ERROR;
}
}
return SQLITE_OK;
}
static sqlite3_mutex * _xizi_mtx_alloc(int id)
{
sqlite3_mutex *p = NULL;
switch (id)
{
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE:
p = sqlite3_malloc(sizeof(sqlite3_mutex));
if (p != NULL) {
PrivMutexCreate(&p->mutex, 0);
p->id = id;
}
break;
default:
SQLITE_ASSERT(id - 2 >= 0);
// SQLITE_ASSERT(id - 2 < ArraySize(_static_mutex));
p = &_static_mutex[id - 2];
p->id = id;
break;
}
return p;
}
static void _xizi_mtx_free(sqlite3_mutex * p)
{
SQLITE_ASSERT(p != 0);
PrivMutexDelete(&p->mutex);
switch (p->id) {
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE:
sqlite3_free(p);
break;
default:
break;
}
}
static void _xizi_mtx_enter(sqlite3_mutex *p)
{
SQLITE_ASSERT(p != 0);
PrivMutexObtain(&p->mutex);
}
static int _xizi_mtx_try(sqlite3_mutex *p)
{
SQLITE_ASSERT(p != 0);
if (PrivMutexObtain(&p->mutex) != 0) {
return SQLITE_BUSY;
}
return SQLITE_OK;
}
static void _xizi_mtx_leave(sqlite3_mutex *p)
{
SQLITE_ASSERT(p != 0);
PrivMutexAbandon(&p->mutex);
}
static sqlite3_mutex_methods const *sqlite3DefaultMutex(void)
{
static const sqlite3_mutex_methods sMutex = {
_xizi_mtx_init,
_xizi_mtx_end,
_xizi_mtx_alloc,
_xizi_mtx_free,
_xizi_mtx_enter,
_xizi_mtx_try,
_xizi_mtx_leave,
0,
0
};
return &sMutex;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file xizi_port.h
* @brief support SQLite define for xizi port files
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-25
*/
/*************************************************
File name: xizi_port.h
Description: support SQLite define for xizi port files
Others:
History:
1. Date: 2023-10-25
Author: AIIT XUOS Lab
Modification:
1modify ifndef description
*************************************************/
#ifndef _XIZI_PORT_H_
#define _XIZI_PORT_H_
#include <transform.h>
#include <sqlite_config_xiuos.h>
#include <sqlite3.h>
typedef struct
{
sqlite3_io_methods const *pMethod;
sqlite3_vfs *pvfs;
int fd;
int eFileLock;
int szChunk;
sem_t sem;
} XIZI_SQLITE_FILE_T;
int _xizi_get_temp_name(int nBuf, char *zBuf);
#endif

View File

@ -0,0 +1,668 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file xizi_vfs.c
* @brief support SQLite vfs function in XiZi kernel
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-16
*/
/*************************************************
File name: xizi_vfs.c
Description: support SQLite vfs function in XiZi kernel
Others:
History:
1. Date: 2023-10-16
Author: AIIT XUOS Lab
Modification:
1add xizi vfs function.
*************************************************/
#include "xizi_port.h"
#ifndef SQLITE_OMIT_LOAD_EXTENSION
#error "not support load extension, compile with SQLITE_OMIT_LOAD_EXTENSION."
#endif
#define MAX_PATHNAME 256
/*
** Define various macros that are missing from some systems.
*/
#ifndef O_LARGEFILE
# define O_LARGEFILE 0
#endif
#ifdef SQLITE_DISABLE_LFS
# undef O_LARGEFILE
# define O_LARGEFILE 0
#endif
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
#ifndef RT_USING_NEWLIB
#ifndef EINTR
#define EINTR 4 /* Interrupted system call */
#endif
#ifndef ENOLCK
#define ENOLCK 46 /* No record locks available */
#endif
#ifndef EACCES
#define EACCES 13 /* Permission denied */
#endif
#ifndef EPERM
#define EPERM 1 /* Operation not permitted */
#endif
#ifndef ETIMEDOUT
#define ETIMEDOUT 145 /* Connection timed out */
#endif
#ifndef ENOTCONN
#define ENOTCONN 134 /* Transport endpoint is not connected */
#endif
#if defined(__GNUC__) || defined(__ADSPBLACKFIN__)
int _gettimeofday(struct timeval *tp, void *ignore) __attribute__((weak));
int _gettimeofday(struct timeval *tp, void *ignore)
#elif defined(__CC_ARM)
__weak int _gettimeofday(struct timeval *tp, void *ignore)
#elif defined(__IAR_SYSTEMS_ICC__)
#if __VER__ > 540
__weak
#endif
int _gettimeofday(struct timeval *tp, void *ignore)
#else
int _gettimeofday(struct timeval *tp, void *ignore)
#endif
{
return 0;
}
#endif
static int _Access(const char *pathname, int mode)
{
int fd = -1;
fd = PrivOpen(pathname, O_RDONLY);
if (fd >= 0) {
PrivClose(fd);
return 0;
}
return -1;
}
#define _XIZI_LOG_ERROR(a,b,c) _xizi_log_error_at_line(a,b,c,__LINE__)
static int _xizi_log_error_at_line(
int errcode, /* SQLite error code */
const char *zFunc, /* Name of OS function that failed */
const char *zPath, /* File path associated with error */
int iLine /* Source line number where error occurred */
)
{
char *zErr; /* Message from strerror() or equivalent */
int iErrno = errno; /* Saved syscall error number */
/* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
** the strerror() function to obtain the human-readable error message
** equivalent to errno. Otherwise, use strerror_r().
*/
#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
char aErr[80];
memset(aErr, 0, sizeof(aErr));
zErr = aErr;
/* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined,
** assume that the system provides the GNU version of strerror_r() that
** returns a pointer to a buffer containing the error message. That pointer
** may point to aErr[], or it may point to some static storage somewhere.
** Otherwise, assume that the system provides the POSIX version of
** strerror_r(), which always writes an error message into aErr[].
**
** If the code incorrectly assumes that it is the POSIX version that is
** available, the error message will often be an empty string. Not a
** huge problem. Incorrectly concluding that the GNU version is available
** could lead to a segfault though.
*/
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
zErr =
#endif
strerror_r(iErrno, aErr, sizeof(aErr)-1);
#elif SQLITE_THREADSAFE
/* This is a threadsafe build, but strerror_r() is not available. */
zErr = "";
#else
/* Non-threadsafe build, use strerror(). */
zErr = strerror(iErrno);
#endif
if( zPath==0 )
zPath = "";
sqlite3_log(errcode, "os_xizi.c:%d: (%d) %s(%s) - %s",
iLine, iErrno, zFunc, zPath, zErr);
return errcode;
}
static const char* _xizi_temp_file_dir(void)
{
const char *azDirs[] = {
0,
"/sql",
"/sql/tmp"
"/tmp",
0 /* List terminator */
};
unsigned int i;
struct stat buf;
const char *zDir = 0;
azDirs[0] = sqlite3_temp_directory;
for (i = 0; i < sizeof(azDirs) / sizeof(azDirs[0]); zDir = azDirs[i++])
{
if( zDir == 0 ) continue;
if( PrivStat(zDir, &buf) ) continue;
if( !S_ISDIR(buf.st_mode) ) continue;
break;
}
return zDir;
}
/*
** Create a temporary file name in zBuf. zBuf must be allocated
** by the calling process and must be big enough to hold at least
** pVfs->mxPathname bytes.
*/
int _xizi_get_temp_name(int nBuf, char *zBuf)
{
const unsigned char zChars[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
unsigned int i, j;
const char *zDir;
zDir = _xizi_temp_file_dir();
if (zDir == 0)
{
zDir = ".";
}
/* Check that the output buffer is large enough for the temporary file
** name. If it is not, return SQLITE_ERROR.
*/
if ((strlen(zDir) + strlen("etilqs_") + 18) >= (size_t)nBuf)
{
return SQLITE_ERROR;
}
do {
sqlite3_snprintf(nBuf-18, zBuf, "%s/""etilqs_", zDir);
j = (int)strlen(zBuf);
sqlite3_randomness(15, &zBuf[j]);
for (i = 0; i < 15; i++, j++)
{
zBuf[j] = (char)zChars[((unsigned char)zBuf[j]) % (sizeof(zChars) - 1)];
}
zBuf[j] = 0;
zBuf[j + 1] = 0;
} while (_Access(zBuf, 0) == 0);
return SQLITE_OK;
}
#include "xizi_io_methods.c"
/*
** Invoke open(). Do so multiple times, until it either succeeds or
** fails for some reason other than EINTR.
**
** If the file creation mode "m" is 0 then set it to the default for
** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
** 0644) as modified by the system umask. If m is not 0, then
** make the file creation mode be exactly m ignoring the umask.
**
** The m parameter will be non-zero only when creating -wal, -journal,
** and -shm files. We want those files to have *exactly* the same
** permissions as their original database, unadulterated by the umask.
** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
** transaction crashes and leaves behind hot journals, then any
** process that is able to write to the database will also be able to
** recover the hot journals.
*/
static int _xizi_fs_open(const char *file_path, int f, mode_t m)
{
int fd = -1;
while (fd < 0)
{
fd = PrivOpen(file_path, f);
if (fd < 0)
{
if (errno == EINTR)
continue;
break;
}
}
return fd;
}
static int _xizi_vfs_open(sqlite3_vfs *pvfs, const char *file_path, sqlite3_file *file_id, int flags, int *pOutFlags)
{
XIZI_SQLITE_FILE_T *p;
int fd;
int eType = flags & 0xFFFFFF00; /* Type of file to open */
int rc = SQLITE_OK; /* Function Return Code */
int openFlags = 0;
mode_t openMode = 0;
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
int isCreate = (flags & SQLITE_OPEN_CREATE);
int isReadonly = (flags & SQLITE_OPEN_READONLY);
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
/* If argument zPath is a NULL pointer, this function is required to open
** a temporary file. Use this buffer to store the file name in.
*/
char zTmpname[MAX_PATHNAME + 2];
p = (XIZI_SQLITE_FILE_T*)file_id;
/* Check the following statements are true:
**
** (a) Exactly one of the READWRITE and READONLY flags must be set, and
** (b) if CREATE is set, then READWRITE must also be set, and
** (c) if EXCLUSIVE is set, then CREATE must also be set.
** (d) if DELETEONCLOSE is set, then CREATE must also be set.
*/
SQLITE_ASSERT((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
SQLITE_ASSERT(isCreate==0 || isReadWrite);
SQLITE_ASSERT(isExclusive==0 || isCreate);
SQLITE_ASSERT(isDelete==0 || isCreate);
/* The main DB, main journal, WAL file and master journal are never
** automatically deleted. Nor are they ever temporary files. */
SQLITE_ASSERT( (!isDelete && file_path) || eType!=SQLITE_OPEN_MAIN_DB );
SQLITE_ASSERT( (!isDelete && file_path) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
SQLITE_ASSERT( (!isDelete && file_path) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
SQLITE_ASSERT( (!isDelete && file_path) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
SQLITE_ASSERT( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
|| eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
/* Database filenames are double-zero terminated if they are not
** URIs with parameters. Hence, they can always be passed into
** sqlite3_uri_parameter(). */
SQLITE_ASSERT((eType != SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) || file_path[strlen(file_path) + 1] == 0);
memset(p, 0, sizeof(XIZI_SQLITE_FILE_T));
if (!file_path)
{
rc = _xizi_get_temp_name(MAX_PATHNAME + 2, zTmpname);
if (rc != SQLITE_OK )
{
return rc;
}
file_path = zTmpname;
/* Generated temporary filenames are always double-zero terminated
** for use by sqlite3_uri_parameter(). */
SQLITE_ASSERT(file_path[strlen(file_path) + 1] == 0);
}
/* Determine the value of the flags parameter passed to POSIX function
** open(). These must be calculated even if open() is not called, as
** they may be stored as part of the file handle and used by the
** 'conch file' locking functions later on. */
if (isReadonly) openFlags |= O_RDONLY;
if (isReadWrite) openFlags |= O_RDWR;
if (isCreate) openFlags |= O_CREAT;
if (isExclusive) openFlags |= (O_EXCL | O_NOFOLLOW);
openFlags |= (O_LARGEFILE | O_BINARY);
fd = _xizi_fs_open(file_path, openFlags, openMode);
if (fd < 0 && (errno != -EISDIR) && isReadWrite && !isExclusive)
{
/* Failed to open the file for read/write access. Try read-only. */
flags &= ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
openFlags &= ~(O_RDWR | O_CREAT);
flags |= SQLITE_OPEN_READONLY;
openFlags |= O_RDONLY;
isReadonly = 1;
fd = _xizi_fs_open(file_path, openFlags, openMode);
}
if (fd < 0)
{
// rc = _XIZI_LOG_ERROR(SQLITE_CANTOPEN_BKPT, "open", file_path);
printf("%s line %d open %s fd failed\n", __func__, __LINE__, file_path);
return rc;
}
if (pOutFlags)
{
*pOutFlags = flags;
}
if (isDelete)
{
PrivUnlink(file_path);
}
p->fd = fd;
p->pMethod = &_xizi_io_method;
p->eFileLock = 0;
p->szChunk = 0;
p->pvfs = pvfs;
PrivSemaphoreCreate(&p->sem, 0, 1);
return rc;
}
int _xizi_vfs_delete(sqlite3_vfs* pvfs, const char *file_path, int syncDir)
{
int rc = SQLITE_OK;
if (PrivUnlink(file_path) == (-1))
{
if (errno == -ENOENT)
{
rc = SQLITE_IOERR_DELETE_NOENT;
}
else
{
rc = _XIZI_LOG_ERROR(SQLITE_IOERR_DELETE, "unlink", file_path);
}
return rc;
}
// sync dir: open dir -> fsync -> close
if ((syncDir & 1) != 0)
{
int ii;
int fd = -1;
char zDirname[MAX_PATHNAME + 1];
sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", file_path);
for (ii=(int)strlen(zDirname); ii > 1 && zDirname[ii] != '/'; ii--);
if (ii > 0)
{
zDirname[ii] = '\0';
fd = _xizi_fs_open(zDirname, O_RDONLY | O_BINARY, 0);
}
if (fd >= 0)
{
if (PrivFsync(fd))
{
rc = _XIZI_LOG_ERROR(SQLITE_IOERR_DIR_FSYNC, "fsync", file_path);
}
PrivClose(fd);
}
rc = SQLITE_OK;
}
return rc;
}
static int _xizi_vfs_access(sqlite3_vfs* pvfs, const char *file_path, int flags, int *pResOut)
{
int amode = 0;
#ifndef F_OK
# define F_OK 0
#endif
#ifndef R_OK
# define R_OK 4
#endif
#ifndef W_OK
# define W_OK 2
#endif
switch (flags)
{
case SQLITE_ACCESS_EXISTS:
amode = F_OK;
break;
case SQLITE_ACCESS_READWRITE:
amode = W_OK | R_OK;
break;
case SQLITE_ACCESS_READ:
amode = R_OK;
break;
default:
_XIZI_LOG_ERROR(flags, "access", file_path);
return -1;
}
*pResOut = (_Access(file_path, amode) == 0);
if (flags == SQLITE_ACCESS_EXISTS && *pResOut)
{
struct stat buf;
if (0 == PrivStat(file_path, &buf) && (buf.st_size == 0))
{
*pResOut = 0;
}
}
return SQLITE_OK;
}
static int _xizi_vfs_fullpathname(sqlite3_vfs* pvfs, const char *file_path, int nOut, char *zOut)
{
SQLITE_ASSERT(pvfs->mxPathname == MAX_PATHNAME);
zOut[nOut - 1] = '\0';
if (file_path[0] == '/')
{
sqlite3_snprintf(nOut, zOut, "%s", file_path);
}
else
{
int nCwd;
if (PrivGetcwd(zOut, nOut - 1) == 0)
{
printf("%s line %d get ced %s failed\n", __func__, __LINE__, file_path);
return -1;
}
nCwd = (int)strlen(zOut);
sqlite3_snprintf(nOut - nCwd, &zOut[nCwd], "/%s", file_path);
}
return SQLITE_OK;
}
static int _xizi_vfs_randomness(sqlite3_vfs* pvfs, int nByte, char *zOut)
{
SQLITE_ASSERT((size_t)nByte >= (sizeof(time_t) + sizeof(int)));
memset(zOut, 0, nByte);
{
int i;
char tick8, tick16;
tick8 = (char)PrivGetTickTime();
tick16 = (char)(PrivGetTickTime() >> 8);
for (i = 0; i < nByte; i++)
{
zOut[i] = (char)(i ^ tick8 ^ tick16);
tick8 = zOut[i];
tick16 = ~(tick8 ^ tick16);
}
}
return nByte;
}
static int _xizi_vfs_sleep(sqlite3_vfs* pvfs, int microseconds)
{
int millisecond = (microseconds + 999) / 1000;
PrivTaskDelay(millisecond);
return millisecond * 1000;
}
static int _xizi_vfs_current_time_int64(sqlite3_vfs*, sqlite3_int64*);
static int _xizi_vfs_current_time(sqlite3_vfs* pvfs, double* pnow)
{
sqlite3_int64 i = 0;
int rc;
rc = _xizi_vfs_current_time_int64(0, &i);
*pnow = i / 86400000.0;
return rc;
}
static int _xizi_vfs_get_last_error(sqlite3_vfs* pvfs, int nBuf, char *zBuf)
{
return 0;
}
static int _xizi_vfs_current_time_int64(sqlite3_vfs* pvfs, sqlite3_int64*pnow)
{
#ifndef NO_GETTOD
#define NO_GETTOD 1
#endif
static const sqlite3_int64 rtthreadEpoch = 24405875 * (sqlite3_int64)8640000;
int rc = SQLITE_OK;
#if defined(NO_GETTOD)
time_t t;
time(&t);
*pnow = ((sqlite3_int64)t) * 1000 + rtthreadEpoch;
#else
struct timeval sNow;
if (gettimeofday(&sNow, 0) == 0)
{
*pnow = rtthreadEpoch + 1000 * (sqlite3_int64)sNow.tv_sec + sNow.tv_usec / 1000;
}
else
{
rc = SQLITE_ERROR;
}
#endif
#ifdef SQLITE_TEST
if( sqlite3_current_time )
{
*pnow = 1000 * (sqlite3_int64)sqlite3_current_time + rtthreadEpoch;
}
#endif
return rc;
}
static int _xizi_vfs_set_system_call(sqlite3_vfs* pvfs, const char *file_path, sqlite3_syscall_ptr pfn)
{
return SQLITE_NOTFOUND;
}
static sqlite3_syscall_ptr _xizi_vfs_get_system_call(sqlite3_vfs* pvfs, const char *file_path)
{
return 0;
}
static const char* _xizi_vfs_next_system_call(sqlite3_vfs *pvfs, const char *file_path)
{
return 0;
}
/*
** Initialize and deinitialize the operating system interface.
*/
SQLITE_API int sqlite3_os_init(void)
{
static sqlite3_vfs _xizi_vfs = {
3, /* iVersion */
sizeof(XIZI_SQLITE_FILE_T), /* szOsFile */
MAX_PATHNAME, /* mxPathname */
0, /* pNext */
"xiuos", /* zName */
0, /* pAppData */
_xizi_vfs_open, /* xOpen */
_xizi_vfs_delete, /* xDelete */
_xizi_vfs_access, /* xAccess */
_xizi_vfs_fullpathname, /* xFullPathname */
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
_xizi_vfs_randomness, /* xRandomness */
_xizi_vfs_sleep, /* xSleep */
_xizi_vfs_current_time, /* xCurrentTime */
_xizi_vfs_get_last_error, /* xGetLastError */
_xizi_vfs_current_time_int64, /* xCurrentTimeInt64 */
_xizi_vfs_set_system_call, /* xSetSystemCall */
_xizi_vfs_get_system_call, /* xGetSystemCall */
_xizi_vfs_next_system_call, /* xNextSystemCall */
};
sqlite3_vfs_register(&_xizi_vfs, 1);
return SQLITE_OK;
}
SQLITE_API int sqlite3_os_end(void)
{
return SQLITE_OK;
}

View File

@ -14,7 +14,9 @@
time_t time(time_t *t)
{
NULL_PARAM_CHECK(t);
if (NULL == t) {
return 0;
}
time_t current = 0;
#ifdef RESOURCES_RTC

View File

@ -449,7 +449,7 @@ int open(const char *path, int flags, ...)
abspath = GetAbsolutePath(path);
mp = GetMountPoint(abspath);
if (mp == NULL) {
SYS_ERR("%s: mount point not found\n", __func__);
SYS_ERR("%s: mount point not found path %s abspath %s\n", __func__, path, abspath);
ret = -EINVAL;
goto err;
}

View File

@ -555,6 +555,11 @@ ifeq ($(CONFIG_LIB_USING_CJSON), y)
KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/lib/cJSON
endif
ifeq ($(CONFIG_LIB_USING_SQLITE), y)
KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/lib/SQLite #
KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/lib/SQLite/xizi_port #
endif
ifeq ($(CONFIG_LIB_USING_LORAWAN), y)
ifeq ($(CONFIG_LIB_USING_LORA_RADIO), y)
KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/lib/lorawan/lora_radio_driver/lora-radio/common #

View File

@ -412,7 +412,7 @@ The STM32F4x7 allows computing and verifying the IP, UDP, TCP and ICMP checksums
- To use this feature let the following define uncommented.
- To disable it and process by CPU comment the the checksum.
*/
// #define CHECKSUM_BY_HARDWARE
#define CHECKSUM_BY_HARDWARE
#ifdef CHECKSUM_BY_HARDWARE
/* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/

View File

@ -31,7 +31,7 @@ static void PrintOctal(char *str, int len, uint64_t value)
char *cp;
int written_len;
written_len = sprintf(buf, "%0*llo", len, value);
written_len = sprintf(buf, "%0*lo", len, value);
cp = buf + written_len - len;
if (*cp == '0')