OpenHarmony开发者论坛

标题: 快速使用C语言操作sqlite3介绍 [打印本页]

作者: 润开鸿_闻飞    时间: 2024-7-2 11:53
标题: 快速使用C语言操作sqlite3介绍
[md][itopen组织](https://gitee.com/itopen)
1、提供OpenHarmony优雅实用的小工具
2、手把手适配riscv + qemu + linux的三方库移植
3、未来计划riscv + qemu + ohos的三方库移植 + 小程序开发
4、一切拥抱开源,拥抱国产化

# 一、sqlite3库介绍

sqlite3库可从官网下载,当前版本为sqlite3 3.45.3
[https://www.sqlite.org/download.html](https://www.sqlite.org/download.html)

# 二、sqlite3编译

## 2.1 x86_64架构安装

### 2.1.1 命令安装

```shell
sudo apt-get install sqlite3
sudo apt-get install libsqlite3-dev
```

### 2.1.2 源码编译安装

```shell
./configure
make -j$(nproc)
sudo make install
```

## 2.2 基于arm架构编译

### 2.2.1 下载工具链并安装

```shell
# 下载工具链
wget https://repo.huaweicloud.com/ope ... inux-gnueabi.tar.gz
tar -xvf prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi.tar.gz

# 设置工具链的路径
vim ~/.bashrc
# 最后一行添加
export PATH=~/bin/prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi/binPATH
# 重置.bashrc
source ~/.bashrc
```

### 2.2.2 编译sqlite3

```shell
export CC=aarch64-linux-gnu-gcc
./configure --prefix=$PWD/_install CC=aarch64-linux-gnu-gcc --host=aarch64-linux
./configure --prefix=$PWD/_install
make -j$(nproc)
make install
```

## 2.3 基于riscv64架构编译

### 2.3.1 工具链安装

```shell
sudo apt-get install gcc-riscv64-linux-gnu
```

### 2.3.2 编译sqlite3

```shell
./configure --prefix=$PWD/_install CC=riscv64-linux-gnu-gcc --host=riscv64-linux
make -j$(nproc)
make install
```

# 三、接口介绍

参考链接:
[https://geek-docs.com/sqlite](https://geek-docs.com/sqlite)

## 3.1 打开/创建数据库

```c
int sqlite3_open(const char *filename, sqlite3 **ppDb);
```

## 3.2 关闭数据库

```c
int sqlite3_close(sqlite3 *db);
```

## 3.3 执行sql语句

```c
int sqlite3_exec(sqlite3*,
                 const char *sql,
                 int (*callback)(void *, int, char **, char **),
                 void *arg,
                 char **errmsg);
```

## 3.4 获取结果内容

```c
int sqlite3_get_table(sqlite3 *db,
                      const char *zSql,
                      char ***pazResult,
                      int *pnRow,
                      int *pnColumn,
                      char **pzErrmsg);
```

## 3.5 获取错误信息

```c
const char *sqlite3_errmsg(sqlite3 *db);
```

## 3.6 释放表空间

```c
void sqlite3_free_table(char **result);
```

# 四、sqlite3语句

## 4.1 sqlite数据类型

```shell
NULL:标识一个NULL值
INTEGER(intger):整数类型 int
REAL(real):浮点数 float,double
TEXT(text):字符串 ""
CHAR(char):字符''
```

## 4.2 创建表

```shell
create if not exists table table_name(column1 type1, column2 type2, column3 type3……);
# 例如创建一个名为dictory的表(sheet),里面有word、translation等字段
create table if not exists table_name(word text, translation text);

# not null 指定列不允许为NULL值
create table if not exists student(student_name txt not NULL, id txt not NULL, sex char);

# default 在insert into语句没有提供特定的值时,为列提供一个默认值
create table if not exists student(student_name txt not NULL, id txt not NULL, sex char, grade integer default 99);

# unique 约束防止一个特定的列存在两个相同的值
create table if not exists student(student_name txt not NULL unique, id txt not NULL, sex char);

# check 约束 启用输入一条记录要检查值的条件。如果条件值为false,则记录违反了约束,且不能输入到表
create table if not exists student(student_name txt not NULL, id txt not NULL, sex char, grade intger check(grade > 0));
```

## 4.3 添加记录

```shell
insert into table_name(column1, column2, column3) values(val1, val2, val3);
insert into student(student_name, id, sex) values ('z3', '123', 'm');
或者
insert into student values('z3', '123', 'm');
```

## 4.4 查询

### 4.4.1 查看表结构

```shell
.schema
```

### 4.4.2 查看所有表

```shell
.tables
```

### 4.4.3 查看记录

```shell
# 获取所有数据记录
select * from table_name;

# 限制输出数据记录数量
select * from table_name limit val;

# 升序输出数据记录
select * from table_name order by column asc;
select * from dictory order by word asc;

# 降序输出数据记录
select * from table_name order by column desc;
select * from dictory order by word desc;

# 条件查询
select * from table_name where expression;
select * from table_name where column in ('val1', 'val2', 'val3');
select * from table_name where column = 'val1' or column = 'val2';
select * from table_name where column between val1 and val2;
select * from people where age>=10 and age <=15;
select name, age from people where age>= 10 and age<=15;
select * from table_name where column like 'xx%' or 'xxx_';
百分号(%)代表零个、一个或者多个数字或字符
下划线(_)代表一个单一数字或字符
```

## 4.5 修改数据记录

```shell
update table_name set column1=val1, column2=val2 where expression;
update student_info set id=0002, name=hencai where id=0001;
```

## 4.6 表中添加字段

```shell
alter table <table_name> add column <field> <type>;
alter table stu add column age integer;
```

## 4.7 删除数据记录

```shell
delete from table_name [where expression];
delete from stu where id=123;
```

## 4.8 删除表

```shell
drop table table_name;
drop table student;
```

## 4.9 删除指定字段

```shell
# step1:备份为temp id , name , age , sex
alter table info rename to temp;

# step2:创建新表
create table info(id, name, age);

#step3:导出到新表
insert into info select id, name, age from temp;
```

## 4.10 退出sqlite3

```
.quit
```

# 五、sqlite3库封装

## 5.1 封装库代码

**代码来源 [itopen组织:  test](https://gitee.com/itopen/test/tree/master/third_party/sqlite3)**

sqlite3_lib.c代码

```c
#include "sqlite3_lib.h"

struct Sqlite3SyncOps sqlite3Sync[] = {
    {SQLITE3_SYNC_MODE_FULL, "RAGMA synchronous = FULL"},
    {SQLITE3_SYNC_MODE_NORMAL, "RAGMA synchronous = NORMAL"},
    {SQLITE3_SYNC_MODE_OFF, "RAGMA synchronous = OFF"},
};

int CreateDatabase(char *dbname, sqlite3 **db)
{
    int ret = sqlite3_open(dbname, db);
    if (ret != SQLITE_OK) {
        printf("sqlite3_open error: %s\n", sqlite3_errmsg(*db));
        return -1;
    }
    return SQLITE_OK;
}

int SetDatabaseSync(sqlite3 *db, enum Sqlite3SyncMode mode)
{
    char *errmsg = NULL;
    if (db == NULL) {
        printf("db is NULL\n");
        return -1;
    }

    if (sqlite3_exec(db, sqlite3Sync[mode].sql, NULL, NULL, &errmsg)) {
        printf("sqlite3_exec error: %s\n", errmsg);
        sqlite3_free(errmsg);
        return -1;
    }

    return SQLITE_OK;
}

int CreateDataSheet(sqlite3 *db, const char *sql)
{
    char *errmsg = NULL;
    if (db == NULL) {
        printf("db is NULL\n");
        return -1;
    }

    if (sqlite3_exec(db, sql, NULL, NULL, &errmsg)) {
        printf("sqlite3_exec error: %s\n", errmsg);
        sqlite3_free(errmsg);
        return -1;
    }
    return SQLITE_OK;
}

int InsertDataValue(sqlite3 *db, const char *sheet, const char *column, const char *value)
{
    int i;
    char sql[1024];
    char *errmsg = NULL;
    if (db == NULL) {
        printf("db is NULL\n");
        return -1;
    }

    sprintf(sql, "insert into %s(%s) values (%s);", sheet, column, value);
    printf("sql: %s\n", sql);

    if (sqlite3_exec(db, sql, NULL, NULL, &errmsg)) {
        printf("sqlite3_exec error: %s\n", errmsg);
        sqlite3_free(errmsg);
        return -1;
    }

    return SQLITE_OK;
}

int CloseDatabase(sqlite3 *db)
{
    if (db == NULL) {
        return 0;
    }
    return sqlite3_close(db);
}


```

sqlite3_lib.h代码

```c
#ifndef __SQLITE3_LIB_H__
#define __SQLITE3_LIB_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>

enum Sqlite3SyncMode {
    // 在每次写入操作完成之前,会等待数据被写入磁盘后再继续下一步操作。这种模式具有最高的数据完整性和可靠性,但性能会受到一定影响
    SQLITE3_SYNC_MODE_FULL = 0,
    // 在写入操作完成之后,会等待数据被写入磁盘的操作系统缓存中后再继续下一步操作。这种模式在数据完整性和性能之间达到了一种平衡,适用于大多数场景
    SQLITE3_SYNC_MODE_NORMAL,
    // 在写入操作完成后,不会等待数据被写入磁盘,直接继续下一步操作。这种模式具有最高的性能,但数据的完整性和可靠性可能会受到一定影响。适用于对数据完整性要求不高的场景,例如缓存数据
    SQLITE3_SYNC_MODE_OFF
};

struct Sqlite3SyncOps {
    int id;
    char *sql;
};

int CreateDatabase(char *dbname, sqlite3 **db);
int SetDatabaseSync(sqlite3 *db, enum Sqlite3SyncMode mode);
int CreateDataSheet(sqlite3 *db, const char *sql);
int InsertDataValue(sqlite3 *db, const char *sheet, const char *column, const char *value);
int CloseDatabase(sqlite3 *db);

#endif /* end of __SQLITE3_LIB_H__ */
```

Makefile代码

```makefile
#************************************************************************
#> File Name: Makefile.c
#> Author: Wenfei6316
#> Mail: wen_fei@hoperun.com
#> Created Time: 2024年07月1日 星期一 03时44分36秒
#************************************************************************

sqlite3_lib:
        gcc sqlite3_lib.c -fPIC -shared -o libsqlite3_lib.so


all: sqlite3_lib ECHO
        gcc main.c -o main -lsqlite3 -L./ -lsqlite3_lib

ECHO:
        @echo $(SUBDIR)
        @echo "========>begin compile"

clean:
        find ./ -name "*.o" -exec rm {} \;
```

# 六、Demo样例

## 6.1 dictory创建

```shell
#include "sqlite3_lib.h"

#define CREATE_TABLE "create table if not exists dict(word text primary key, translation text);"

int main(int argc, char **argv)
{
    int i;
    int cnt = 1;
    int ret;
    FILE *fp = NULL;
    sqlite3 *db = NULL;
    char buf[1024] = {0};
    char value[1024] = {0};
    printf("start create database\n");
    // 1. 创建数据库
    ret = CreateDatabase("dictionary.db", &db);
    if (ret != SQLITE_OK) {
        printf("CreateDatabase error: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    // 2. 设置数据库同步模式
    ret = SetDatabaseSync(db, SQLITE3_SYNC_MODE_FULL);
    if (ret != SQLITE_OK) {
        printf("SetDatabaseSync error: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    // 3. 常见表格
    ret = CreateDataSheet(db, CREATE_TABLE);
    if (ret != SQLITE_OK) {
        printf("CreateDataSheet error: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    // 4. 插入数据
    fp = fopen("dict.txt", "r");
    if (fp == NULL) {
        printf("open dict.txt error\n");
        return -1;
    }

    while (fgets(buf, sizeof(buf), fp) != NULL) {
        if (buf[strlen(buf)-1] == '\n') {
            buf[strlen(buf)-1] = '\0';
        }

        // 获取单词结尾地方并设置为\0, 以及翻译起始位置
        for (i = 0; buf != ' '; i++);
        buf = '\0';
        for(; buf[++i] == ' ';);

        // 插入数据到数据库
        snprintf(value, 1024, "\"%s\", \"%s\"", &buf[0], &buf);
        printf("%d: value: %s\n", cnt++, value);
        ret = InsertDataValue(db, "dict", "word, translation", value);
        if (ret != SQLITE_OK) {
            printf("InsertDataValue error: %s\n", sqlite3_errmsg(db));
            return -1;
        }

        memset(buf, '\0', sizeof(buf));
        memset(value, '\0', sizeof(value));
    }

    fclose(fp);
    CloseDatabase(db);
    printf("close database success\n");
    return 0;
}
```

# 附录

另有Python简单封装的sqlite3操作可参见 [itopen组织: module_code](https://gitee.com/itopen/module_ ... /python/database.py)
[/md]




欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5