Просмотр исходного кода

1.修复SQLite软件包在RTT3.1.3以上版本的兼容性问题。
2.加入dbhelper及DAO层示例,以使应用开发使用时更加简单便捷。
3.基于以上修改SConscript文件及撰写README。

lizhen9880 6 лет назад
Родитель
Сommit
498306385b
8 измененных файлов с 1360 добавлено и 4 удалено
  1. 319 2
      README.md
  2. 4 1
      SConscript
  3. 522 0
      dbhelper.c
  4. 120 0
      dbhelper.h
  5. 2 1
      rtthread_io_methods.c
  6. 2 0
      sqlite_config_rtthread.h
  7. 347 0
      student_dao.c
  8. 44 0
      student_dao.h

+ 319 - 2
README.md

@@ -1,2 +1,319 @@
-# SQLite
-SQLite is a self-contained, high-reliability, embedded, full-featured, public-domain, SQL database engine.
+# SQLite 
+
+## 简介 
+
+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(虚拟文件系统)接口                     |
+| dbhelper.c               | sqlite3操作接口封装,简化应用                                    |
+| dbhelper.h               | dbhelper头文件,向外部声明封装后的接口,供用户调用               |
+| student_dao.c            | 简单的DAO层例程,简单展示了对dbhelper的使用方法                  |
+| student_dao.h            | 数据访问对象对外接口声明,线程可通过调用这些接口完成对该表的操作 |
+
+## 获取
+
+在ENV中配置如下
+
+```c
+RT-Thread online packages  ---> 
+    system packages  ---> 
+        --- SQLite: a self-contained, high-reliability, embedded, full-featured, public-domain, SQL database engine.
+        (/rt.db) Database name(path)
+        (1024) SQL statements max length
+        [*]   Enable example
+```
+
+配置项说明:
+
+| 名称                      | 说明                                                                                  |
+| ------------------------- | ------------------------------------------------------------------------------------- |
+| Database name(path)       | 数据库文件名称,应包含文件路径及文件名,默认将数据库文件存放在根目录下,文件名为rt.db |
+| SQL statements max length | SQL语句最大长度,请根据实际业务需求设置。                                             |
+| Enable example            | 选择是否使能DAO层例程,例程是模拟了学生成绩录入查询                                   |
+
+## 依赖
+- RT-Thread 3.X+
+- DFS组件
+## dbhelp接口说明
+
+dbhelp是对sqlite3操作接口的封装,目的是使用户更加简单地操作sqlite。
+### 初始化
+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_*(此处*为通配符,取值为int,double,text等,详情请见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 |
+| ...                    | 变参                                                              |
+| 返回                   |                                                                   |
+| SQLITE_OK或SQLITE_DONE | 成功                                                              |
+| 其他                   | 失败                                                              |
+
+create回调:
+| 参数                   | 说明                                                 |
+| ---------------------- | ---------------------------------------------------- |
+| stmt                   | sqlite3_stmt预备语句对象                             |
+| arg                    | 接收来由db_query_by_varpara的void *arg传递进来的形参 |
+| 返回                   |                                                      |
+| SQLITE_OK或SQLITE_DONE | 成功                                                 |
+| 其他                   | 失败                                                 |
+
+用户可通过调用在通过调用db_stmt_get_int,db_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        | 不存在   |
+| 负值     | 查询错误 |
+
+## 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)

+ 4 - 1
SConscript

@@ -2,8 +2,11 @@ from building import *
 
 
 cwd = GetCurrentDir()
 cwd = GetCurrentDir()
 src = ['sqlite3.c']
 src = ['sqlite3.c']
-CPPPATH = [cwd]
+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)
 group = DefineGroup('sqlite', src, depend = ['RT_USING_DFS', 'PKG_USING_SQLITE'], CPPPATH = CPPPATH)
 
 
 Return('group')
 Return('group')

+ 522 - 0
dbhelper.c

@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-03-06     lizhen9880   first version
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <rtthread.h>
+#include <ctype.h>
+#include "dbhelper.h"
+#define DBG_ENABLE
+#define DBG_SECTION_NAME "app.dbhelper"
+#define DBG_LEVEL DBG_INFO
+#define DBG_COLOR
+#include <rtdbg.h>
+
+static rt_mutex_t db_mutex_lock = RT_NULL;
+
+/**
+ * This function will initialize SQLite3 create a mutex as a lock.
+ */
+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);
+
+/**
+ * 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.
+ * @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, ...)
+{
+    sqlite3 *db = NULL;
+    sqlite3_stmt *stmt = NULL;
+    if (sql == NULL)
+    {
+        return -RT_ERROR;
+    }
+    rt_mutex_take(db_mutex_lock, RT_WAITING_FOREVER);
+    int rc = sqlite3_open(DB_NAME, &db);
+    if (rc != SQLITE_OK)
+    {
+        LOG_E("open database failed,rc=%d", rc);
+        rt_mutex_release(db_mutex_lock);
+        return rc;
+    }
+
+    rc = sqlite3_prepare(db, sql, -1, &stmt, NULL);
+    if (rc != SQLITE_OK)
+    {
+        LOG_E("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)
+        {
+            LOG_E("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:
+    LOG_E("db operator failed,rc=%d", rc);
+    rc = 0;
+__db_exec_ok:
+    sqlite3_close(db);
+    rt_mutex_release(db_mutex_lock);
+    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.
+ * @param param the parameter for the callback "bind".
+ * @return  success or 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;
+    }
+    rt_mutex_take(db_mutex_lock, RT_WAITING_FOREVER);
+    int rc = sqlite3_open(DB_NAME, &db);
+    if (rc != SQLITE_OK)
+    {
+        LOG_E("open database failed,rc=%d", rc);
+        rt_mutex_release(db_mutex_lock);
+        return rc;
+    }
+    rc = sqlite3_exec(db, "begin transaction", 0, 0, NULL);
+    if (rc != SQLITE_OK)
+    {
+        LOG_E("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)
+            {
+                LOG_E("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)
+        {
+            LOG_E("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))
+        {
+            LOG_E("bind failed");
+            goto __db_exec_fail;
+        }
+    }
+    rc = sqlite3_exec(db, "commit transaction", 0, 0, NULL);
+    if (rc)
+    {
+        LOG_E("commit transaction:%d", rc);
+        goto __db_exec_fail;
+    }
+    goto __db_exec_ok;
+
+__db_exec_fail:
+    if (sqlite3_exec(db, "rollback transaction", 0, 0, NULL))
+    {
+        LOG_E("rollback transaction error");
+    }
+
+__db_begin_fail:
+    LOG_E("db operator failed,rc=%d", rc);
+
+__db_exec_ok:
+    sqlite3_close(db);
+    rt_mutex_release(db_mutex_lock);
+    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  success or 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;
+    }
+    rt_mutex_take(db_mutex_lock, RT_WAITING_FOREVER);
+    int rc = sqlite3_open(DB_NAME, &db);
+    if (rc != SQLITE_OK)
+    {
+        LOG_E("open database failed,rc=%d\n", rc);
+        rt_mutex_release(db_mutex_lock);
+        return rc;
+    }
+    LOG_D("sql:%s", sql);
+    rc = sqlite3_prepare(db, sql, -1, &stmt, NULL);
+    if (rc != SQLITE_OK)
+    {
+        LOG_E("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))
+    {
+        LOG_E("bind error,rc=%d", rc);
+        goto __db_exec_fail;
+    }
+    rc = 0;
+    goto __db_exec_ok;
+
+__db_exec_fail:
+    LOG_E("db operator failed,rc=%d", rc);
+
+__db_exec_ok:
+    sqlite3_close(db);
+    rt_mutex_release(db_mutex_lock);
+    return rc;
+}
+
+/**
+ * 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)
+{
+    sqlite3 *db = NULL;
+
+    rt_mutex_take(db_mutex_lock, RT_WAITING_FOREVER);
+    int rc = sqlite3_open(DB_NAME, &db);
+    if (rc != SQLITE_OK)
+    {
+        LOG_E("open database failed,rc=%d", rc);
+        rt_mutex_release(db_mutex_lock);
+        return rc;
+    }
+    rc = sqlite3_exec(db, "begin transaction", 0, 0, NULL);
+    if (rc != SQLITE_OK)
+    {
+        LOG_E("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))
+    {
+        LOG_E("prepare error,rc=%d", rc);
+        goto __db_exec_fail;
+    }
+
+    rc = sqlite3_exec(db, "commit transaction", 0, 0, NULL);
+    if (rc)
+    {
+        LOG_E("commit transaction:%d", rc);
+        goto __db_exec_fail;
+    }
+    goto __db_exec_ok;
+
+__db_exec_fail:
+    if (sqlite3_exec(db, "rollback transaction", 0, 0, NULL))
+    {
+        LOG_E("rollback transaction:error");
+    }
+
+__db_begin_fail:
+    LOG_E("db operator failed,rc=%d", rc);
+
+__db_exec_ok:
+    sqlite3_close(db);
+    rt_mutex_release(db_mutex_lock);
+    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  the count or 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 -RT_ERROR;
+}
+
+/**
+ * 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)
+{
+    const char *pdata = sqlite3_column_blob(stmt, index);
+    int len = sqlite3_column_bytes(stmt, index);
+    if (pdata)
+    {
+        memcpy(out, pdata, len);
+        return len;
+    }
+    return -RT_ERROR;
+}
+
+/**
+ * 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)
+{
+    const unsigned char *pdata = sqlite3_column_text(stmt, index);
+    if (pdata)
+    {
+        int len = strlen((char *)pdata);
+        strncpy(out, (char *)pdata, len);
+        return len;
+    }
+    return -RT_ERROR;
+}
+
+/**
+ * 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 == RT_NULL)
+    {
+        return -RT_ERROR;
+    }
+    rt_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 -RT_ERROR;
+}

+ 120 - 0
dbhelper.h

@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2006-2020, 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>
+#define DB_NAME PKG_SQLITE_DB_NAME
+#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);
+#endif

+ 2 - 1
rtthread_io_methods.c

@@ -267,7 +267,7 @@ static int _rtthread_io_unlock(sqlite3_file *file_id, int eFileLock)
 
 
     /* no, really unlock. */
     /* no, really unlock. */
     rt_sem_release(psem);
     rt_sem_release(psem);
-
+    
     file->eFileLock = NO_LOCK;
     file->eFileLock = NO_LOCK;
     return SQLITE_OK;
     return SQLITE_OK;
 }
 }
@@ -280,6 +280,7 @@ static int _rtthread_io_close(sqlite3_file *file_id)
     if (file->fd >= 0)
     if (file->fd >= 0)
     {
     {
         _rtthread_io_unlock(file_id, NO_LOCK);
         _rtthread_io_unlock(file_id, NO_LOCK);
+        rt_sem_detach(&file->sem);
         rc = close(file->fd);
         rc = close(file->fd);
         file->fd = -1;
         file->fd = -1;
     }
     }

+ 2 - 0
sqlite_config_rtthread.h

@@ -11,6 +11,8 @@
 
 
 #define SQLITE_OMIT_WAL 1
 #define SQLITE_OMIT_WAL 1
 
 
+#define SQLITE_OMIT_AUTOINIT 1
+
 #ifndef SQLITE_RTTHREAD_NO_WIDE
 #ifndef SQLITE_RTTHREAD_NO_WIDE
 #define SQLITE_RTTHREAD_NO_WIDE 1
 #define SQLITE_RTTHREAD_NO_WIDE 1
 #endif
 #endif

+ 347 - 0
student_dao.c

@@ -0,0 +1,347 @@
+/*
+ * 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
+ */
+
+#include <rtthread.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dfs_posix.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
+#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;
+    rt_list_init(q);
+    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)
+        {
+            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:
+    student_free_list(q);
+    return 0;
+}
+
+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);
+    int ret = student_get_all(h);
+    student_print_list(h);
+    rt_kprintf("record(s):%d\n", ret);
+    student_free_list(h);
+    rt_free(h);
+}
+
+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_kprintf("the student list of score between %d and %d:\n", ls, hs);
+    int ret = student_get_by_score(h, ls, hs, order);
+    student_print_list(h);
+    student_free_list(h);
+    rt_kprintf("record(s):%d\n", ret);
+}
+
+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 != 0)
+            {
+                rt_kprintf("add failed!");
+            }
+
+            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() == 0)
+                {
+                    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) == 0)
+                {
+                    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) == 0)
+                {
+                    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 = open(DB_NAME, O_RDONLY);
+    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);

+ 44 - 0
student_dao.h

@@ -0,0 +1,44 @@
+/*
+ * 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__
+
+#include <rtthread.h>
+
+struct student
+{
+    unsigned int id;
+    char name[32];
+    int score;
+    rt_list_t list;
+};
+typedef struct student student_t;
+
+/**  
+ * ASC:Ascending 
+ * DESC:Descending 
+ * */
+enum order_type
+{
+    ASC = 0,
+    DESC = 1,
+};
+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