SQLite C/C++ 接口简介

  • A+
所属分类:编程

1总结 以下两个对象和八个方法构成了 SQLite 接口的基本元素:

sqlite3 → 数据库连接对象。由 sqlite3_open() 创建并由 sqlite3_close() 销毁。

sqlite3_stmt → 准备好的语句对象。由 sqlite3_prepare() 创建并由 sqlite3_finalize() 销毁。

sqlite3_open() → 打开与新的或现有的 SQLite 数据库的连接。 sqlite3 的构造函数。

sqlite3_prepare() → 将 SQL 文本编译成字节码,以完成查询或更新数据库的工作。 sqlite3_stmt 的构造函数。

sqlite3_bind() → 将应用程序数据存储到原始 SQL 的参数中。

sqlite3_step() → 将 sqlite3_stmt 推进到下一个结果行或完成。

sqlite3_column() → sqlite3_stmt 的当前结果行中的列值。

sqlite3_finalize() → sqlite3_stmt 的析构函数。

sqlite3_close() → sqlite3 的析构函数。

sqlite3_exec() → 一个包装函数,它对一个或多个 SQL 语句的字符串执行 sqlite3_prepare()、sqlite3_step()、sqlite3_column() 和 sqlite3_finalize()。

2简介

SQLite 有超过 225 个 API。 但是,大多数 API 是可选的且非常专业,初学者可以忽略。 核心 API 小巧、简单且易于学习。本文总结了核心API。

单独的文档 SQLite C/C++ 接口提供了 SQLite 的所有 C/C++ API 的详细规范。 一旦读者理解了 SQLite 的基本操作原理,就可以将该文档用作参考指南。
本文仅作介绍,既不是 SQLite API 的完整参考,也不是权威参考

3核心对象和接口

SQL 数据库引擎的主要任务是评估 SQL 的 SQL 语句。 为此,开发人员需要两个对象:

 数据库连接对象:sqlite3
 准备好的语句对象:sqlite3_stmt

严格来说,不需要准备好的语句对象,因为可以使用便利包装器接口 sqlite3_exec 或 sqlite3_get_table,并且这些便利包装器封装和隐藏准备好的语句对象。
然而,需要了解准备好的语句才能充分利用 SQLite。数据库连接和准备好的语句对象由下面列出的一小组 C/C++ 接口例程控制。

sqlite3_open()
sqlite3_prepare()
sqlite3_step()
sqlite3_column()
sqlite3_finalize()
sqlite3_close()

请注意,上面的例程列表是概念性的,而不是实际的。 许多这些例程都有多个版本。 例如,上面的列表显示了一个名为 sqlite3_open() 的例程,而实际上有三个单独的例程以略有不同的方式完成相同的事情:sqlite3_open()、sqlite3_open16() 和 sqlite3_open_v2()。 该列表提到 sqlite3_column() 实际上不存在这样的例程。
列表中显示的“sqlite3_column()”是整个例程系列的占位符,这些例程以各种数据类型添加列数据。

以下是核心接口功能的摘要:
sqlite3_open()
此例程打开一个到 SQLite 数据库文件的连接并返回一个数据库连接对象。 这通常是应用程序进行的第一个 SQLite API 调用,并且是大多数其他 SQLite API 的先决条件。
许多 SQLite 接口需要一个指向数据库连接对象的指针作为它们的第一个参数,可以将其视为数据库连接对象上的方法。 该例程是数据库连接对象的构造函数。

sqlite3_prepare()
此例程将 SQL 文本转换为准备好的语句对象并返回指向该对象的指针。 该接口需要一个由先前调用 sqlite3_open() 创建的数据库连接指针和一个包含要准备的 SQL 语句的文本字符串。 此 API 实际上并不评估 SQL 语句。 它只是准备用于评估的 SQL 语句。
将每个 SQL 语句视为一个小型计算机程序。 sqlite3_prepare() 的目的是将该程序编译为目标代码。 准备好的语句是目标代码。 sqlite3_step() 接口然后运行目标代码以获得结果。

新应用程序应始终调用 sqlite3_prepare_v2() 而不是 sqlite3_prepare()。 保留旧的 sqlite3_prepare() 是为了向后兼容。 但是 sqlite3_prepare_v2() 提供了更好的界面。

sqlite3_step()
此例程用于评估先前由 sqlite3_prepare() 接口创建的准备好的语句。 该语句被评估到第一行结果可用的点。 要前进到第二行结果,请再次调用 sqlite3_step()。
继续调用 sqlite3_step() 直到语句完成。 不返回结果的语句(例如:INSERT、UPDATE 或 DELETE 语句)在一次调用 sqlite3_step() 时运行完成。

sqlite3_column()
这个例程从结果集的当前行返回一个单列,用于由 sqlite3_step() 评估的准备好的语句。 每次 sqlite3_step() 以新的结果集行停止时,可以多次调用此例程以查找该行中所有列的值。

如上所述,SQLite API 中确实没有像“sqlite3_column()”这样的函数。 相反,我们这里所说的“sqlite3_column()”是整个函数系列的占位符,这些函数从各种数据类型的结果集中返回一个值。 该系列中还有一些例程可返回结果的大小(如果它是字符串或 BLOB)和结果集中的列数。

sqlite3_column_blob()
sqlite3_column_bytes()
sqlite3_column_bytes16()
sqlite3_column_count()
sqlite3_column_double()
sqlite3_column_int()
sqlite3_column_int64()
sqlite3_column_text()
sqlite3_column_text16()
sqlite3_column_type()
sqlite3_column_value()

sqlite3_finalize()
该例程销毁由先前调用 sqlite3_prepare() 创建的准备好的语句。 必须使用对该例程的调用来销毁每个准备好的语句,以避免内存泄漏。

sqlite3_close()
此例程关闭先前通过调用 sqlite3_open() 打开的数据库连接。 所有与连接相关的准备好的语句都应该在关闭连接之前完成。

4核心例程和对象的典型用法

应用程序通常会在初始化期间使用 sqlite3_open() 创建单个数据库连接。 请注意, sqlite3_open() 可用于打开现有数据库文件或创建和打开新数据库文件。 虽然许多应用程序只使用单个数据库连接,但没有理由应用程序不能多次调用 sqlite3_open() 以打开多个数据库连接 - 无论是到同一个数据库还是到不同的数据库。 有时,多线程应用程序会为每个线程创建单独的数据库连接。
请注意,单个数据库连接可以使用 ATTACH SQL 命令访问两个或多个数据库,因此不必为每个数据库文件都设置单独的数据库连接。

许多应用程序在关闭时使用对 sqlite3_close() 的调用来破坏它们的数据库连接。 或者,例如,使用 SQLite 作为其应用程序文件格式的应用程序可能会打开数据库连接以响应 File/Open 菜单操作,
然后销毁相应的数据库连接以响应 File/Close 菜单。

要运行 SQL 语句,应用程序遵循以下步骤:

 1使用 sqlite3_prepare() 创建一个准备好的语句。
 2通过调用 sqlite3_step() 一次或多次来评估准备好的语句。
 3对于查询,通过在两次调用 sqlite3_step() 之间调用 sqlite3_column() 来提取结果。
 4使用 sqlite3_finalize() 销毁准备好的语句。  

为了有效地使用 SQLite,上述内容是人们真正需要知道的。 剩下的就是优化和细节。

5核心例程的便利包装

sqlite3_exec() 接口是一个方便的包装器,它通过单个函数调用执行上述所有四个步骤。 传递给 sqlite3_exec() 的回调函数用于处理结果集的每一行。 sqlite3_get_table() 是另一个方便的包装器,可以完成上述所有四个步骤。 sqlite3_get_table() 接口与 sqlite3_exec() 的不同之处在于它将查询结果存储在堆内存中,而不是调用回调。

重要的是要意识到 sqlite3_exec() 和 sqlite3_get_table() 都不能做任何使用核心例程无法完成的事情。 事实上,这些包装器纯粹是根据核心例程来实现的。

6绑定参数和重用准备好的语句

在前面的讨论中,假设每个 SQL 语句都准备一次,评估,然后销毁。 但是,SQLite 允许多次评估同一个准备好的语句。 这是使用以下例程完成的:

sqlite3_reset()
sqlite3_bind()

在通过一次或多次调用 sqlite3_step() 评估准备好的语句后,可以重置它,以便通过调用 sqlite3_reset() 再次评估。 将 sqlite3_reset() 视为将准备好的语句程序倒回到开头。
在现有的准备好的语句上使用 sqlite3_reset() 而不是创建新的准备好的语句可以避免对 sqlite3_prepare() 的不必要调用。 对于很多 SQL 语句,运行 sqlite3_prepare() 所需的时间等于或超过 sqlite3_step() 所需的时间。
因此,避免调用 sqlite3_prepare() 可以显着提高性能。

多次评估完全相同的 SQL 语句通常没有用。 更多的时候,人们想要评估类似的陈述。 例如,您可能希望使用不同的值多次评估 INSERT 语句。 或者,您可能希望使用 WHERE 子句中的不同键多次评估同一查询。
为了适应这一点,SQLite 允许 SQL 语句包含在被评估之前“绑定”到值的参数。 稍后可以更改这些值,并且可以使用新值再次评估相同的准备好的语句。

SQLite 允许在任何允许字符串文字、数字常量或 NULL 的地方使用参数。 (参数不能用于列名或表名。)参数采用以下形式之一:

?
?NNN
:AAA
$AAA
@AAA

在上面的例子中,NNN 是一个整数值,AAA 是一个标识符。 参数最初的值为 NULL。 在第一次调用 sqlite3_step() 之前或在 sqlite3_reset() 之后立即调用,应用程序可以调用 sqlite3_bind() 接口将值附加到参数。
对 sqlite3_bind() 的每次调用都会覆盖同一参数上的先前绑定。

允许应用程序提前准备多条 SQL 语句并根据需要对其进行评估。 对未完成的准备好的报表数量没有任意限制。 一些应用程序在启动时多次调用 sqlite3_prepare() 来创建他们需要的所有准备好的语句。 其他应用程序保留最近使用的准备好的语句的缓存,
然后在可用时重用缓存中的准备好的语句。 另一种方法是仅在循环内使用准备好的语句。

7 配置 SQLite

SQLite 的默认配置适用于大多数应用程序。 但有时开发人员想要调整设置以尝试提高性能,或者利用一些晦涩的功能。
sqlite3_config() 接口用于对 SQLite 进行全局、进程范围的配置更改。 在创建任何数据库连接之前,必须调用 sqlite3_config() 接口。 sqlite3_config() 接口允许程序员执行以下操作:

调整SQLite进行内存分配的方式,包括设置适用于安全关键的实时嵌入式系统和应用程序定义的内存分配器的替代内存分配器。
设置进程范围的错误日志。
指定应用程序定义的页面缓存。
调整互斥锁的使用,使其适用于各种线程模型,或替代应用程序定义的互斥锁系统。

##创建数据库
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"

//创建数据库example.db,建立PERSON表
int main()
{
    sqlite3* DB;
    char *sql = "CREATE TABLE PERSON("
                      "ID INT PRIMARY KEY     NOT NULL, "
                      "NAME           TEXT    NOT NULL, "
                      "SURNAME          TEXT     NOT NULL, "
                      "AGE            INT     NOT NULL, "
                      "ADDRESS        CHAR(50), "
                      "SALARY         REAL );";
    int exit = 0;
    exit = sqlite3_open("example.db", &DB);
    char* messaggeError;
    exit = sqlite3_exec(DB, sql, NULL, 0, &messaggeError);
    if (exit!= SQLITE_OK)
    {
        printf("error\n");
        sqlite3_free(messaggeError);
    }
    else
    {
        printf("success!\n");
    }
    sqlite3_close(DB);
    return 0;
}

## 2使用sql语句
static int callback(void* data, int argc, char** argv, char** azColName)
{
    int i;
    fprintf(stderr, "%s: ", (const char*)data);

    for (i = 0; i < argc; i++) 
    {
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }

    printf("\n");
    return 0;
}

int main()
{
    sqlite3* DB;
    char* messaggeError;
    int exit = sqlite3_open("example.db", &DB);
    char * query = "SELECT * FROM PERSON ;";
    printf("插入之前表的状态\n");

    sqlite3_exec(DB, query, callback, NULL, NULL);

    char *sql ="INSERT INTO PERSON VALUES(1, 'STEVE', 'GATES', 30, 'PALO ALTO', 1000.0);"
                "INSERT INTO PERSON VALUES(2, 'BILL', 'ALLEN', 20, 'SEATTLE', 300.22);"
                "INSERT INTO PERSON VALUES(3, 'PAUL', 'JOBS', 24, 'SEATTLE', 9900.0);";

    exit = sqlite3_exec(DB, sql, NULL, 0, &messaggeError);
    if (exit != SQLITE_OK) 
    {
        printf("Error Insert\n" );
        sqlite3_free(messaggeError);
    }
    else
        printf("Records 成功创造\n");

    printf("插入表之后的状态\n");

    sqlite3_exec(DB, query, callback, NULL, NULL);

    sql = "DELETE FROM PERSON WHERE ID = 2;";
    exit = sqlite3_exec(DB, sql, NULL, 0, &messaggeError);
    if (exit != SQLITE_OK) 
    {
        printf("Error DELETE\n");
        sqlite3_free(messaggeError);
    }
    else
        printf("Record deleted Successfully!\n");

    printf("删除records之后表的状态\n");
    sqlite3_exec(DB, query, callback, NULL, NULL);
    sqlite3_close(DB);
    return (0);
}

//动态绑定值-insert
//using prepare statement --insert
int main()
{

int rc;
sqlite3 *db;
sqlite3_stmt *stmt = NULL;
int id_num=49;
int exit = 0;
int bind_index=0;
char * y[7]={"2013","11","12","19","09","52","20131112190952"};

// create the sql statement, with a single placeholder marked by '?'.
char *sql ="INSERT INTO IMG VALUES(?, ?, ?, ?, ?, ?, ?, ?);";

exit = sqlite3_open("image.db", &db);

// prepare the sql statement.
rc = sqlite3_prepare_v2(db, sql, strlen(sql)+1, &stmt, NULL);
if (rc != SQLITE_OK)
{
    printf("Failed to prepare statement: %s\n\r", sqlite3_errstr(rc));
    sqlite3_close(db);
    return 1;
}
else
{
    printf("SQL statement prepared: OK\n\n\r");
}

//bind init   sqlite3_bind_int(stmt, 1, id_num);
for(;bind_index<(sizeof(y) / sizeof(char *));bind_index++)
{

    sqlite3_bind_text(stmt,bind_index+2,y[bind_index],strlen(y[bind_index]),NULL);
}

if (rc != SQLITE_OK)
{
    printf("Failed to bind parameter: %s\n\r", sqlite3_errstr(rc));
    sqlite3_close(db);
    return 1;
}
else
{
    printf("SQL bind integer param: OK\n\n\r");
}

// evaluate the prepared statement.
rc = sqlite3_step(stmt);

if (rc != SQLITE_DONE)
{
    printf("Failed to execute statement: %s\n\r", sqlite3_errstr(rc));
    sqlite3_close(db);
    return 1;
}
else
{
    printf("%d\n",sqlite3_column_int(stmt,4));
    printf("%s\n",sqlite3_column_text(stmt,4));
    printf("%s\n",sqlite3_column_text(stmt,5));
}

// deallocate/finalize the prepared statement when you no longer need it.
// you may also place this in any error handling sections.
sqlite3_finalize(stmt);

// close the db when finished.
 sqlite3_close(db);
}

//using prepare statement--select
int main()
{

    int rc;
    sqlite3 *db;
    sqlite3_stmt *stmt = NULL;
    int id_num=40;
    char * y1="2022";
    char *m1 = "10";
    int exit = 0;
    char *sql = "SELECT * FROM IMG  WHERE year1=? and month1=?";
    exit = sqlite3_open("image.db", &db);
    // prepare the sql statement.
    rc = sqlite3_prepare_v2(db, sql, strlen(sql)+1, &stmt, NULL);
    if (rc != SQLITE_OK)
    {
        printf("Failed to prepare statement: %s\n\r", sqlite3_errstr(rc));
        sqlite3_close(db);
        return 1;
    }
    else
    {
        printf("SQL statement prepared: OK\n\n\r");
    }
    //bind int    sqlite3_bind_int(stmt, 1, id_num);
    rc = sqlite3_bind_text(stmt, 1, y1, 4, NULL);
    rc = sqlite3_bind_text(stmt, 2, m1, strlen(m1), NULL);
    printf("m1 length is%d\n",strlen(m1));
    if (rc != SQLITE_OK)
    {
        printf("Failed to bind parameter: %s\n\r", sqlite3_errstr(rc));
        sqlite3_close(db);
        return 1;
    }
    else
    {
        printf("SQL bind integer param: OK\n\n\r");
    }
    //search all
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
        printf("%d\n",sqlite3_column_int(stmt,4));
        printf("%s\n",sqlite3_column_text(stmt,1));
        printf("%s\n",sqlite3_column_text(stmt,2));
        printf("%s\n",sqlite3_column_text(stmt,3));
        printf("%s\n",sqlite3_column_text(stmt,4));
        printf("%s\n",sqlite3_column_text(stmt,7));
    }

    if (rc != SQLITE_DONE)
    {
        printf("Failed to execute statement: %s\n\r", sqlite3_errstr(rc));
        sqlite3_close(db);
        return 1;
    }
    // deallocate/finalize the prepared statement when you no longer need it.
    // you may also place this in any error handling sections.
    sqlite3_finalize(stmt);

    // close the db when finished.
    sqlite3_close(db);
}

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main()
{
    int bind_index;
    char * y[5]={"2022","10","30","200934","20221030200934"};
    y[1]="11";
    printf("%d\n",sizeof(*y));
    printf("%d\n",sizeof(y));
    printf("%d\n",sizeof(y) / sizeof(char *));
    for(bind_index=0;bind_index<sizeof(y);bind_index++)
    {
        printf("%d\t%d\t%s\n",bind_index,sizeof(y[bind_index]),y[bind_index]);
        printf("%d\t%d\t%s\n",bind_index,strlen(y[bind_index]),y[bind_index]);
    }
        printf("Hello world!\n");
    return 0;
}

int main()
{
    int bind_index;
    char * y[5];
    for(bind_index=0;bind_index<5;bind_index++)
    {

        y[bind_index]=(char*)malloc(sizeof(char)*100);
    }
    //y[0]="dfdg";

    //y[1]="sdfd45674574578486865";
    strcpy(y[0],"789857349856739867983768934769837698376398467347986");
    printf("%x\t%s\n",y[0],y[0]);
}

int main()
{
    int bind_index;
    char * y[5]={NULL};
/**字符串不能直接赋值*/    
    //y[0]="dfdg";
    //y[1]="sdfd45674574578486865";
    strcpy(y[0],"789857349856739867983768934769837698376398467347986");
    printf("%x\t%s\n",y[0],y[0]);
}

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: