sqlite3

SQLite是一个C语言库,它实现了一个小型、快速、自包含、高可靠性、功能齐全的SQL数据库引擎。

SQLite是世界上使用最多的数据库引擎。SQLite内置于所有手机和大多数计算机中,并捆绑在人们每天使用的无数其他应用程序中。更多信息。。。

SQLite文件格式稳定、跨平台、向后兼容,开发人员承诺在2050年保持这种格式。SQLite数据库文件通常用作容器,在系统之间传输丰富的内容,并作为数据的长期存档格式[4]。目前有超过1万亿(1e12)个SQLite数据库在使用[5]。

SQLite源代码属于公共领域,每个人都可以自由地用于任何目的。

下载、编译、安装

下载

可以去 sqlite 官方网站:官方网站 找到下载版本进行下载,也可以直接点击这里提供的 下载链接(sqlite-snapshot-202108231028.tar)

linux 环境下编译、安装

将下载后的压缩包在 linux 操作系统环境下进行解压:

$ tar -xvf sqlite-snapshot-202108231028.tar.gz 
# 这里由于我需要 32 位的静态库,所以添加了 --enable-static 和 CC="gcc -m32" 参数
$ ../configure --enable-static --prefix=/home/ww/ww/gitlabproject/opcodetester/third/sqlite/ CC="gcc -m32"
$ make && make install

编译安装完成后,得到如下目录:

本地数据库 sqlite3 编译和使用_sqlite

C/C++ 使用示例

使用 sqlite3 的整个过程其实和操作 MySQL 等数据库的方式是相同的,需要先创建或者打开本地数据库,然后就是通过数据库操作语法实现数据库的增删改查操作了。

sqlite3 C/C++ 接口

数据库创建/打开操作

首先,必须了解 sqlite3 的打开/创建数据库接口,具体使用方式参考如下代码:

	sqlite3 *sql = NULL; // 一个打开的数据库实例
    const char * path = "test.db";//某个sql文件的路径

    // 根据文件路径打开数据库连接。如果数据库不存在,则创建。
    // 数据库文件的路径必须以C字符串传入。
    int result = sqlite3_open_v2(path, &sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL);
    // int result = sqlite3_open(path, &sql);

    if (result == SQLITE_OK) {
        std::cout << "打开数据库连接成功" << endl;;
    }
    else {
        std::cout << "打开数据库连接失败" << endl;
    }

通过函数 sqlite3_open_v2() 能够创建并且打开本地数据库,第一个参数是本地数据库的路径文件名。具体接口的声明如下:

SQLITE_API int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
SQLITE_API int sqlite3_open16(
  const void *filename,   /* Database filename (UTF-16) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
SQLITE_API int sqlite3_open_v2(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb,         /* OUT: SQLite db handle */
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
);

数据库正常操作

通过打开数据库操作 sqlite3_open() 获得了 ppDb 的数据库对象(句柄),接下来就是将组织好的数据库操作语言使用接口函数对数据库进行操作

相关接口的具体声明如下:

SQLITE_API int sqlite3_prepare(
  sqlite3 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);
SQLITE_API int sqlite3_prepare_v2(
  sqlite3 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);
SQLITE_API int sqlite3_prepare_v3(
  sqlite3 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);
SQLITE_API int sqlite3_prepare16(
  sqlite3 *db,            /* Database handle */
  const void *zSql,       /* SQL statement, UTF-16 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const void **pzTail     /* OUT: Pointer to unused portion of zSql */
);
SQLITE_API int sqlite3_prepare16_v2(
  sqlite3 *db,            /* Database handle */
  const void *zSql,       /* SQL statement, UTF-16 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const void **pzTail     /* OUT: Pointer to unused portion of zSql */
);
SQLITE_API int sqlite3_prepare16_v3(
  sqlite3 *db,            /* Database handle */
  const void *zSql,       /* SQL statement, UTF-16 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const void **pzTail     /* OUT: Pointer to unused portion of zSql */
);

使用的参考代码如下:

	const char *sqlSentence = "INSERT INTO t_person(name, age) VALUES('夏明', 22); ";        //SQL语句
    sqlite3_stmt *stmt = NULL;        //stmt语句句柄
	//进行插入前的准备工作——检查语句合法性
    //-1代表系统会自动计算SQL语句的长度
    result = sqlite3_prepare_v2(sql, sqlSentence, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
        std::clog<< "添加数据语句OK";
        //执行该语句
        sqlite3_step(stmt);
    }
    else {
        std::clog << "添加数据语句有问题";
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);

其中,在开始的部分需要首先拼好一个 SQL 语句,这里使用的语句为:
INSERT INTO t_person(name, age) VALUES('夏明', 22); 表示向 t_person 表中插入数据 name='夏明', age=22 的数据。如果是新创建的空白数据库,注意需要先创建数据表才能开始进行数据的增删改查啊。

知道了如何通过 SQL 语句实现对数据库的操作后,我们来看一下 SQL 语句的使用。(这里,可以参考菜鸟学堂进行的总结:sqlite3 菜鸟教程

创建表

语法

CREATE TABLE 语句的基本语法如下:

CREATE TABLE database_name.table_name(
   column1 datatype  PRIMARY KEY(one or more columns),
   column2 datatype,
   column3 datatype,
   .....
   columnN datatype,
);

CREATE TABLE 是告诉数据库系统创建一个新表的关键字。CREATE TABLE 语句后跟着表的唯一的名称或标识。您也可以选择指定带有 table_name 的 database_name。

实例

下面是一个实例,它创建了一个 COMPANY 表,ID 作为主键,NOT NULL 的约束表示在表中创建纪录时这些字段不能为 NULL:

sqlite> CREATE TABLE COMPANY(
   ID INT PRIMARY KEY     NOT NULL,
   NAME           TEXT    NOT NULL,
   AGE            INT     NOT NULL,
   ADDRESS        CHAR(50),
   SALARY         REAL
);

下面是一个实例,它创建了一个 COMPANY 表,ID 作为主键,NOT NULL 的约束表示在表中创建纪录时这些字段不能为 NULL:

sqlite> CREATE TABLE COMPANY(
   ID INT PRIMARY KEY     NOT NULL,
   NAME           TEXT    NOT NULL,
   AGE            INT     NOT NULL,
   ADDRESS        CHAR(50),
   SALARY         REAL
);

C/C++ 中使用

    const char *sqlCreatetable = "CREATE TABLE t_person(name TEXT PRIMARY KEY NOT NULL, age INTEGER);";
    sqlite3_stmt *stmt = NULL;        //stmt语句句柄
    result = sqlite3_prepare_v2(sql, sqlCreatetable, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
        std::clog<< "创建数据表成功" << endl;
        //执行该语句
        sqlite3_step(stmt);
    }
    else {
        std::clog << "创建数据表失败" << endl;
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);

删除表

SQLite 的 DROP TABLE 语句用来删除表定义及其所有相关数据、索引、触发器、约束和该表的权限规范。( 使用此命令时要特别注意,因为一旦一个表被删除,表中所有信息也将永远丢失。)

语法

DROP TABLE 语句的基本语法如下。您可以选择指定带有表名的数据库名称,如下所示:

DROP TABLE database_name.table_name;

实例

让我们先确认 COMPANY 表已经存在,然后我们将其从数据库中删除。

sqlite>.tables
COMPANY       test.COMPANY

这意味着 COMPANY 表已存在数据库中,接下来让我们把它从数据库中删除,如下:

sqlite>DROP TABLE COMPANY;
sqlite>

现在,如果尝试 .TABLES 命令,那么将无法找到 COMPANY 表了:

sqlite>.tables
sqlite>

显示结果为空,意味着已经成功从数据库删除表。

C/C++ 中使用

    const char *sqlCreatetable = "DROP  TABLE  t_person;";
    sqlite3_stmt *stmt = NULL;        //stmt语句句柄
    result = sqlite3_prepare_v2(sql, sqlCreatetable, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
        std::clog<< "删除数据表成功" << endl;
        //执行该语句
        sqlite3_step(stmt);
    }
    else {
        std::clog << "删除数据表失败" << endl;
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);

插入语句

SQLite 的 INSERT INTO 语句用于向数据库的某个表中添加新的数据行。(这个表一定要先创建出来才可以正常执行插入数据)

语法

INSERT INTO 语句有两种基本语法,如下所示:

INSERT INTO TABLE_NAME [(column1, column2, column3,...columnN)]  
VALUES (value1, value2, value3,...valueN);

在这里,column1, column2,…columnN 是要插入数据的表中的列的名称。

如果要为表中的所有列添加值,您也可以不需要在 SQLite 查询中指定列名称。但要确保值的顺序与列在表中的顺序一致。SQLite 的 INSERT INTO 语法如下:

INSERT INTO TABLE_NAME VALUES (value1,value2,value3,...valueN);

实例

假设您已经在 testDB.db 中创建了 COMPANY表,如下所示:

sqlite> CREATE TABLE COMPANY(
   ID INT PRIMARY KEY     NOT NULL,
   NAME           TEXT    NOT NULL,
   AGE            INT     NOT NULL,
   ADDRESS        CHAR(50),
   SALARY         REAL
);

现在,下面的语句将在 COMPANY 表中创建六个记录:

INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)
VALUES (1, 'Paul', 32, 'California', 20000.00 );

INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)
VALUES (2, 'Allen', 25, 'Texas', 15000.00 );

INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)
VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );

INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)
VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 );

INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)
VALUES (5, 'David', 27, 'Texas', 85000.00 );

INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)
VALUES (6, 'Kim', 22, 'South-Hall', 45000.00 );

您也可以使用第二种语法在 COMPANY 表中创建一个记录,如下所示:

INSERT INTO COMPANY VALUES (7, 'James', 24, 'Houston', 10000.00 );

上面的所有语句将在 COMPANY 表中创建下列记录。下一章会教您如何从一个表中显示所有这些记录。

ID          NAME        AGE         ADDRESS     SALARY
----------  ----------  ----------  ----------  ----------
1           Paul        32          California  20000.0
2           Allen       25          Texas       15000.0
3           Teddy       23          Norway      20000.0
4           Mark        25          Rich-Mond   65000.0
5           David       27          Texas       85000.0
6           Kim         22          South-Hall  45000.0
7           James       24          Houston     10000.0

使用一个表来填充另一个表

您可以通过在一个有一组字段的表上使用 select 语句,填充数据到另一个表中。下面是语法:

INSERT INTO first_table_name [(column1, column2, ... columnN)] 
   SELECT column1, column2, ...columnN 
   FROM second_table_name
   [WHERE condition];

C/C++ 中使用

	const char *sqlSentence = "INSERT INTO t_person(name, age) VALUES('夏明', 22); ";        //SQL语句
    //进行插入前的准备工作——检查语句合法性
    //-1代表系统会自动计算SQL语句的长度
    result = sqlite3_prepare_v2(sql, sqlSentence, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
        std::clog<< "添加数据语句OK" << endl;
        //执行该语句
        sqlite3_step(stmt);
    }
    else {
        std::clog << "添加数据语句有问题" << endl;
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);

查询语句

SQLite 的 SELECT 语句用于从 SQLite 数据库表中获取数据,以结果表的形式返回数据。这些结果表也被称为结果集。

语法

SQLite 的 SELECT 语句的基本语法如下:

SELECT column1, column2, columnN FROM table_name;

在这里,column1, column2…是表的字段,他们的值即是您要获取的。如果您想获取所有可用的字段,那么可以使用下面的语法:

SELECT * FROM table_name;

实例

假设 COMPANY 表有以下记录:

ID          NAME        AGE         ADDRESS     SALARY
----------  ----------  ----------  ----------  ----------
1           Paul        32          California  20000.0
2           Allen       25          Texas       15000.0
3           Teddy       23          Norway      20000.0
4           Mark        25          Rich-Mond   65000.0
5           David       27          Texas       85000.0
6           Kim         22          South-Hall  45000.0
7           James       24          Houston     10000.0

下面是一个实例,使用 SELECT 语句获取并显示所有这些记录。在这里,前两个个命令被用来设置正确格式化的输出。

sqlite>.header on
sqlite>.mode column
sqlite> SELECT * FROM COMPANY;

最后,将得到以下的结果:

ID          NAME        AGE         ADDRESS     SALARY
----------  ----------  ----------  ----------  ----------
1           Paul        32          California  20000.0
2           Allen       25          Texas       15000.0
3           Teddy       23          Norway      20000.0
4           Mark        25          Rich-Mond   65000.0
5           David       27          Texas       85000.0
6           Kim         22          South-Hall  45000.0
7           James       24          Houston     10000.0

如果只想获取 COMPANY 表中指定的字段,则使用下面的查询:

sqlite> SELECT ID, NAME, SALARY FROM COMPANY;

上面的查询会产生以下结果:

ID          NAME        SALARY
----------  ----------  ----------
1           Paul        20000.0
2           Allen       15000.0
3           Teddy       20000.0
4           Mark        65000.0
5           David       85000.0
6           Kim         45000.0
7           James       10000.0

设置输出列的宽度

有时,由于要显示的列的默认宽度导致 .mode column,这种情况下,输出被截断。此时,您可以使用 .width num, num… 命令设置显示列的宽度,如下所示:

sqlite>.width 10, 20, 10
sqlite>SELECT * FROM COMPANY;

上面的 .width 命令设置第一列的宽度为 10,第二列的宽度为 20,第三列的宽度为 10。因此上述 SELECT 语句将得到以下结果:

ID          NAME                  AGE         ADDRESS     SALARY
----------  --------------------  ----------  ----------  ----------
1           Paul                  32          California  20000.0
2           Allen                 25          Texas       15000.0
3           Teddy                 23          Norway      20000.0
4           Mark                  25          Rich-Mond   65000.0
5           David                 27          Texas       85000.0
6           Kim                   22          South-Hall  45000.0
7           James                 24          Houston     10000.0

Schema 信息

因为所有的点命令只在 SQLite 提示符中可用,所以当您进行带有 SQLite 的编程时,您要使用下面的带有 sqlite_master 表的 SELECT 语句来列出所有在数据库中创建的表:

sqlite> SELECT tbl_name FROM sqlite_master WHERE type = 'table';

假设在 testDB.db 中已经存在唯一的 COMPANY 表,则将产生以下结果:

tbl_name
----------
COMPANY

您可以列出关于 COMPANY 表的完整信息,如下所示:

sqlite> SELECT sql FROM sqlite_master WHERE type = 'table' AND tbl_name = 'COMPANY';

假设在 testDB.db 中已经存在唯一的 COMPANY 表,则将产生以下结果:

CREATE TABLE COMPANY(
   ID INT PRIMARY KEY     NOT NULL,
   NAME           TEXT    NOT NULL,
   AGE            INT     NOT NULL,
   ADDRESS        CHAR(50),
   SALARY         REAL
)

C/C++ 中使用

result = sqlite3_prepare_v2(sql, sqlSentence1, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
        std::clog <<  "查询语句OK";
            // 每调一次sqlite3_step()函数,stmt语句句柄就会指向下一条记录
            while (sqlite3_step(stmt) == SQLITE_ROW) {
                // 取出第0列字段的值
                const unsigned char *name = sqlite3_column_text(stmt, 0);
                // 取出第1列字段的值
                int age = sqlite3_column_int(stmt, 1);
                //输出相关查询的数据
                std::clog << "name = " << name <<", age = "<< age << endl;
            }
    }
    else {
        std::clog << "查询语句有问题" << endl;
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);

条件查询语句

运算语句

更新语句

删除语句

关闭数据库操作

在使用完成数据库后,最好正常关闭数据库,而 C/C++ 中关闭数据库的操作接口如下:

SQLITE_API int sqlite3_close(sqlite3*);
SQLITE_API int sqlite3_close_v2(sqlite3*);

代码中操作如下:

    if (sql) 
    {
        sqlite3_close_v2(sql);
        sql = nullptr;
    }
代码工程使用

添加 sqlite 库文件到工程下

在工程目录 third 下创建 sqlite 库相关文件存放的目录路径 third/sqlite ,如下:

本地数据库 sqlite3 编译和使用_big data_02

修改 Cmake 配置文件

# sqlite3
set(SQLITELIB_PATH ${PROJECT_SOURCE_DIR}/third/sqlite)
list(APPEND SQLITE_LIBS_INCLUDE ${SQLITELIB_PATH}/include)
list(APPEND SQLITE_LIBS_INCLUDE ${SQLITELIB_PATH}/include/log4c)
link_directories(${SQLITELIB_PATH}/lib)
link_libraries(sqlite3)

...

#添加头文件引用路径
target_include_directories(opcodetester PUBLIC
                           ${PROJECT_BINARY_DIR}
                           ${EXTRA_INCLUDE}
                           ${SQLITE_LIBS_INCLUDE }
												)

工程中代码使用

这里首先是在一个测试程序中用到了数据库(针对X86 opcode 指令集测试),所以将设计如下的数据表内容:

数据名称 类型 含义
instruction 字符类型 【助记符名称】测试指令对应的助记符名称,例如 “ADD” “SUB” “CMP” 等
opcode 字节类型 【opcode】这条指令对应的 opcode ,Opcode 可能存在不止一个字节,所以这里需要存放一组字节数据
true_result 数据类型 REAL 【正确执行结果】该指令在 X86 机器上运行的计算结果,作为测试结果是否正确的评定标准
param1 数据类型 REAL 参数1 该指令在使用时所需的参数1
param2 数据类型 REAL 参数1 该指令在使用时所需的参数2
param3 数据类型 REAL 参数1 该指令在使用时所需的参数3
param4 数据类型 REAL 参数1 该指令在使用时所需的参数4

创建数据库和构造的相关代码如下:

#ifndef     _COMMON_DATABASE__H
#define     _COMMON_DATABASE__H

#include "sqlite3.h"
#include "base.hpp"
#include "debug.hpp"

class Database
{
private:
    sqlite3         *sql;
    sqlite3_stmt    *stmt;
    char            *mydbfilename;

public:
    Database(const char *dbfilename = "test.db");
    ~Database();

    int insert(const char *ins, const char *op, double *result);
    int selectIns(const char *ins, const char *opcode, double* &result);
    

private:
    int myDataOpen(const char *dbfilename);
    bool myDataClose(void);
    bool myDataCreateTable(void);
    bool myDataDropTable(void);
    bool myDataInsetData(const char *instruction, const char *opcode, double *true_reslut);
    bool myDataSelectData(void);

};

int Database::selectIns(const char *ins, const char *opcode, double* &result)
{

    int ret = 0;
    const char *sqlSentence1 = "SELECT * FROM t_opcode WHERE instruction == '%s' AND  opcode == '%s';";    //SQL语句
    char select_buf[1024] = {0};

    sprintf(select_buf, sqlSentence1, ins, opcode);

    //进行查询前的准备工作——检查语句合法性
    //-1代表系统会自动计算SQL语句的长度
    ret = sqlite3_prepare_v2(sql, select_buf, -1, &stmt, NULL);

    if (ret == SQLITE_OK) {
        Log.INFO("查询语句OK");
        // 每调一次sqlite3_step()函数,stmt语句句柄就会指向下一条记录
        while (sqlite3_step(stmt) == SQLITE_ROW) 
        {
            result[0] = sqlite3_column_double(stmt, 2);
            result[1] = sqlite3_column_double(stmt, 3);
            result[2] = sqlite3_column_double(stmt, 4);
            result[3] = sqlite3_column_double(stmt, 5);
        }
    }
    else {
        Log.INFO("查询语句有问题");
        return -1;
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);

    return 0;
}

int Database::insert(const char *ins, const char *op, double *result)
{
    myDataInsetData(ins, op, result);
    return 0;
}

bool Database::myDataSelectData(void)
{
    int result = 0;
    const char *sqlSentence1 = "SELECT * FROM t_opcode WHERE age < 30;";    //SQL语句
    std::string tmp;
    char buf[1024] = {0};

    //进行查询前的准备工作——检查语句合法性
    //-1代表系统会自动计算SQL语句的长度
    result = sqlite3_prepare_v2(sql, sqlSentence1, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
        Log.INFO("查询语句OK");
        // 每调一次sqlite3_step()函数,stmt语句句柄就会指向下一条记录
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            // 取出第0列字段的值
            const unsigned char *Instruction = sqlite3_column_text(stmt, 0);

            // 取出第1列字段的值
            const unsigned char *opcode = sqlite3_column_text(stmt, 1);

            float true_result0 = sqlite3_column_double(stmt, 2);
            float true_result1 = sqlite3_column_double(stmt, 2);
            float true_result2 = sqlite3_column_double(stmt, 2);
            float true_result3 = sqlite3_column_double(stmt, 2);

            
            //输出相关查询的数据
            sprintf(buf, "Instruction = [%s], opcode = [%s] true_result = %f - %f - %f - %f ", \
                        Instruction, opcode, true_result0, true_result1, true_result2, true_result3);
            tmp = std::string(buf);
            Log.INFO(tmp);
        }
    }
    else {
        Log.INFO("查询语句有问题");
        return false;
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);

    return true;
}

bool Database::myDataInsetData(const char *instruction, const char *opcode, double *true_reslut)
{
    int result = 0;
    const char *sqlSentence = \
        "INSERT INTO t_opcode(instruction, opcode, true_result0, true_result1, true_result2, true_result3) VALUES ('%s', '%s', %f, %f, %f, %f);";        //SQL语句

    char insert_buf[1024] = {0};

    sprintf(insert_buf, sqlSentence, instruction, opcode, true_reslut[0], true_reslut[1], true_reslut[2], true_reslut[3]);

    //进行插入前的准备工作——检查语句合法性
    //-1代表系统会自动计算SQL语句的长度
    result = sqlite3_prepare_v2(sql, insert_buf, -1, &stmt, NULL);

    if (result == SQLITE_OK) 
    {
        Log.INFO("添加数据语句OK");
        //执行该语句
        sqlite3_step(stmt);
    }
    else 
    {
        Log.INFO("添加数据语句有问题");
        return false;
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);

    return true;
}

bool Database::myDataDropTable()
{
    int result = 0;
    const char *sqlCreatetable = "DROP  TABLE  t_opcode;";
    sqlite3_stmt *stmt = NULL;        //stmt语句句柄
    result = sqlite3_prepare_v2(sql, sqlCreatetable, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
        Log.INFO("删除数据表成功");
        //执行该语句
        sqlite3_step(stmt);
    }
    else {
        Log.INFO("删除数据表失败");
        return false;
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);

    return true;
}

bool Database::myDataCreateTable()
{
    int result = 0;

    /*
    instruction     指令助记符
    opcode          二进制opcode
    true_result0     保存计算结果
    true_result1     保存计算结果
    true_result2     保存计算结果
    true_result3     保存计算结果
    param1          计算参数。。。
    param2
    param3
    param4
    */
    const char *sqlCreatetable = 
        "CREATE TABLE t_opcode(\
            instruction TEXT PRIMARY KEY NOT NULL,\
            opcode TEXT,\
            true_result0	REAL,\
            true_result1	REAL,\
            true_result2	REAL,\
            true_result3	REAL,\
            param1 REAL,\
            param2 REAL,\
            param3 REAL,\
            param4 REAL);";

    result = sqlite3_prepare_v2(sql, sqlCreatetable, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
        Log.INFO("创建数据表成功");
        //执行该语句
        sqlite3_step(stmt);
    }
    else {
        Log.INFO("创建数据表失败");
        return false;
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);
    return true;
}

bool Database::myDataClose()
{
    if(!sql)
    {
        return false;
    }
    sqlite3_close_v2(sql);
    sql = NULL;
    return true;
}

int Database::myDataOpen(const char *dbfilename)
{
    int ret = 0;
    int result = 0;

    /* 判断数据库文件是否存在, 不存在则创建,存在则仅打开 */
    if(!access(dbfilename, F_OK))
    {
        //文件存在
        result = sqlite3_open_v2(dbfilename, &sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL);
    }
    else
    {
        result = sqlite3_open_v2(dbfilename, &sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL);
        ret = 1;
    }
    
    if (result != SQLITE_OK) {
        Log.INFO("打开数据库连接失败");
        return -1;
    }

    Log.INFO("打开数据库连接成功");
    return ret;
}


Database::Database(const char *dbfilename)
{
    int ret = 0;
    sql = NULL;
    stmt = NULL;

    mydbfilename = strdup(dbfilename);
    if(!mydbfilename)
    {
        Log.INFO("数据库文件名初始化失败!");
    }
    else
    {
        Log.INFO("数据库文件名初始化成功!");
    }

    ret = myDataOpen(mydbfilename);
    if(ret < 0)
    {
        Log.INFO("数据库打开失败!");
    }
    else if (ret != 0)
    {    
        myDataCreateTable();
    }

    Log.INFO("数据库打开成功!");

}

Database::~Database()
{
    if(!myDataClose())
    {
        Log.INFO("数据库关闭失败!");
    }
    else
    {
        Log.INFO("数据库关闭成功!");
    }
}





#endif

使用方式:


	Database data;
	data.insert("add", "66 83 0f", result);
	data.insert("addc", "83 0f", result);
	data.selectIns("add", "66 83 0f", p);

	printf("temp  %f - %f - %f - %f \n", temp[0], temp[1], temp[2], temp[3]);

执行结果:

本地数据库 sqlite3 编译和使用_big data_03