Sqlite 与 C/C++ 开发连接方法

Sqlite 与 C/C++

本篇介绍 Windows SqliteC/C++ 开发的连接方法。

本章节不教 SQL 语法。 如尚未学习 SQL 建议与 SQL 混合食用。

下载

  • 前往 Sqlite 官网 SQLite Download Page 下载 Source Code C 语言源代码。
  • 解压安装包到工程目录,得到 shell.c sqlite3.c sqlite3.h sqlite3ext.h,后面主要用到 sqlite3.csqlite3.h

编译

  • 将源文件拷贝到工程目录下的 include/sqlite 目录。

  • 主代码导入头文件 #include "sqlite/sqlite3.h"

  • 然后使用以下两种方法之一用命令行编译(使用其他编译工具其原理都是基于命令行方式的):

    • 直接编译

      gcc main.c include\sqlite\sqlite3.c -o main.exe -I include  # 注意 sqlite3.c 不能使用 g++ 编译
      
    • 动态库编译(PS:静态库也可)

      gcc -c -fpic include\sqlite\sqlite3.c -o sqlite3.o
      gcc -shared sqlite3.o -o libsqlite3.dll
      del sqlite3.o  # 删除编译中间件, 保留 libsqlite3.dll 即可
      g++ main.cpp -o main.exe -I include -L . -l sqlite3  # 之后编译只要这步即可
      

      如果使用动态库编译方法, 后面只需要用到 include\sqlite\sqlite3.hlibsqlite3.dll,请注意保留这两个文件方便之后使用。

  • dll 动态库必须位于工程根目录,不得重命名。(因为我不会其他方法)

接口

Frequent Interface

仅介绍常用接口,足以满足基本开发需求,更多内容建议自行查看 sqlite3.h 头文件或搜索其他 blog

如果看不懂,别急,后面将提供演示。

  • int sqlite3_open(const char *filename, sqlite3 **ppDb)

    打开或创建数据库
    参数:
    	filename:	数据库文件名
    	ppDb: 		数据库对象指针 (二级指针)
    返回值:
    	返回 0, 出现异常返回非 0
    
  • int sqlite3_close(sqlite3 *pDb)

    关闭数据库
    参数:
    	pDb:		数据库对象 (一级指针)
    返回值:
    	返回 0, 出现异常返回非 0
    
  • int sqlite3_errcode(sqlite3 *db)

    获取错误码
    参数:
    	db:			数据库对象
    返回值:
    	返回错误码
    
  • const char *sqlite3_errmsg(sqlite3 *db)

    获取错误信息
    参数:
    	db:			数据库对象
    返回值:
    	返回错误信息 (const char *)
    
  • int sqlite3_exec(sqlite3 *db, const char *sql, int (*callback)(void *, int, char **, char **), void *pArg, char **pErrmsg)

    执行 SQL 语句
    参数:
    	db:			数据库对象
    	sql:		SQL 语句
    	callback:	NULL 或 回调函数, 下面详细介绍
    	pArg:		NULL 或 回调函数的第一项参数
    	errmsg:		NULL 或 传出错误信息 (可用 sqlite3_errmsg 替代, 故无用)
    回调函数: int (*callback)(void *pArg, int nCol, char **cols, char **heads)
    	当 sql 为查询 (SELECT) 语句时调用, 每查询一行信息都会调用一次该函数
    	参数:
    		pArg:		任意参数指针, 由函数外部 pArg 指定传入
    		nCol:		数据列数
    		cols:		行数据指针
    		heads:		标题数据指针
    	返回值:
    		用户自定义返回值, 正常结束要求返回 0, 如返回非 0, 外部函数将中断并返回错误 4: query aborted
    返回值:
    	返回 0, 出现异常返回非 0
    (有点抽象, 建议看 Demo)
    
  • int sqlite3_get_table(sqlite3 *db, const char *sql, char ***pResult, int *pnRow, int *pnColumn, char **pErrmsg)

    获取 SQL 查询结果
    参数:
    	db:			数据库对象
    	sql:		SQL 语句
    	pResult:	结果指针 (三级指针, 顶级用于赋值, 次级用于表示一维列表, 末级表示字符串)
    	pnRow:		行数指针 (不含标题)
    	pnCol:		列数指针
    	pErrmsg:	NULL 或 传出错误信息
    返回:
    	返回 0, 出现异常返回非 0
    (要求 sql 语句为查询语句, 否则请使用 sqlite3_exec, 我也未尝试会出现什么错误)
    
  • void sqlite3_free(void *p)

    释放字符串内存, 如 pErrmsg 属于此类
    如果接收了此类内存指针, 一定别忘记释放
    回调函数接收的内存 及 库函数产生的内存会自动释放, 如 sqlite3_errmsg
    参数:
    	p:			内存指针
    
  • void sqlite3_free_table(char **result)

    释放数据表内存, 即 sqlite3_get_table 接收到的数据表
    如果接受了此类内存指针, 一定别忘记释放
    回调函数接收的内存 及 库函数产生的内存会自动释放, 如 sqlite3_exec 的 rollback 函数
    参数:
    	result:		内存指针
    

Demo

#include <bits/stdc++.h>
#include "sqlite/sqlite3.h"
using namespace std;

int ret;
sqlite3 *pDB = NULL;
char *errMsg = NULL;

// 演示 sqlite3_get_table 获取表信息并打印
void display() {
    char **res;
    int nRow;
    int nCol;
    ret = sqlite3_get_table(pDB, "SELECT * FROM student", &res, &nRow, &nCol, 0);
    if (ret) cout << sqlite3_errmsg(pDB) << endl;
    int idx = 0;  // 注意, 前面提到结果指针表示的是一位数组, 所以我们需要根据 nRow 与 nCol 信息将其作二维解析
    for (int i = -1; i < nRow; i++) {  // -1 行表示标题
        for (int j = 0; j < nCol; j++) {
            char *tmp = res[idx++];
            if (tmp)  // 注意如果为空指针表示表格此处为 NULL
                cout << tmp << '\t';
            else 
                cout << "NULL" << '\t';
        }
        cout << endl;
    }
    sqlite3_free_table(res);  // 别忘了释放内存
}

// 演示 sqlite3_exec 获取表信息并打印
// sqlite3_exec 函数获取表信息时, 每获取一行都会调用一次 回调函数
int callback(void *pArg, int nCol, char **data, char **head) {
    // pArg 可以用于传递任意数据类型指针, 从而实现自由传参, 需要时充分利用
    if (*(bool *)pArg == false) {  // 此处 pArg 用于保证 head 只打印一遍
        for (int i = 0; i < nCol; i++) {
            if (head[i])
                cout << head[i] << '\t';
            else
                cout << "NULL" << '\t';
        }
        cout << endl;
        *(bool *)pArg = true;
    }
    for (int i = 0; i < nCol; i++) {
        if (data[i])
            cout << data[i] << '\t';
        else
            cout << "NULL" << '\t';
    }
    cout << endl;
    return 0;
}

int main() {
    // 连接或创建数据库
    ret = sqlite3_open("Test.db", &pDB);
    if (ret) cout << sqlite3_errmsg(pDB) << endl;
    cout << "Connected successfully!" << endl;
    
    // 创建数据表
    ret = sqlite3_exec(pDB, "CREATE TABLE IF NOT EXISTS student(id int PRIMARY KEY, name varchar(255), birth date)", 0, 0, 0);
    if (ret) cout << sqlite3_errmsg(pDB) << endl;
    
    // 插入一些数据
    ret = sqlite3_exec(pDB, "INSERT INTO student VALUES(1, 'Jamhus Tao', 20041231)", 0, 0, 0);
    if (ret) cout << sqlite3_errmsg(pDB) << endl;
    ret = sqlite3_exec(pDB, "INSERT INTO student VALUES(2, NULL, 20000230)", 0, 0, 0);
    if (ret) cout << sqlite3_errmsg(pDB) << endl;
    ret = sqlite3_exec(pDB, "INSERT INTO student VALUES(3, 'Mike', 20000101)", callback, 0, 0);
    // 注意, 上方回调函数无效, 因为 "INSERT INTO" 不是一个查询语句
    if (ret) cout << sqlite3_errmsg(pDB) << endl;
    
    // 使用 sqlite3_exec 查询并打印
    bool status = false;
    ret = sqlite3_exec(pDB, "SELECT * FROM student", callback, &status, 0);
    if (ret) cout << sqlite3_errmsg(pDB) << endl;
    
    // 使用 sqlite3_get_table 查询并打印
    display();
    
    // 清空数据表
    ret = sqlite3_exec(pDB, "TRUNCATE TABLE student", 0, 0, 0);
    if (ret) cout << sqlite3_errmsg(pDB) << endl;
    
    // 删除数据表
    ret = sqlite3_exec(pDB, "DROP TABLE student", 0, 0, 0);
    if (ret) cout << sqlite3_errmsg(pDB) << endl;
    
    // 关闭数据库连接
    ret = sqlite3_close(pDB);
    if (ret) cout << sqlite3_errmsg(pDB) << endl;
    
    return 0;
}

Output:

Connected successfully!
id	name	birth	
1	Jamhus Tao	20041231	
2	NULL	20000230	
3	Mike	20000101	
id	name	birth	
1	Jamhus Tao	20041231	
2	NULL	20000230	
3	Mike	20000101	
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值