码迷,mamicode.com
首页 > 数据库 > 详细

Linux平台上SQLite数据库教程(二)——C语言API介绍

时间:2015-08-29 23:26:20      阅读:450      评论:0      收藏:0      [点我收藏+]

标签:sqlite   linux-c   c语言   

Linux平台上SQLite数据库教程(二)——C语言API介绍

前言:本文将介绍几个基本的SQLite3数据库的C语言API接口,主要用到两个文件:sqlite3.c、sqlite3.h。源码地址:https://github.com/AnSwErYWJ/SQLite

打开数据库

1.原型:

int sqlite3_open(
    const char* filename,    /* 数据库文件名, 必须为 UTF-8 格式 */
    sqlite3** ppDB            /* 输出: SQLite 数据库句柄 */
);;

2.说明:
参数filename为指定打开的数据库, sqlite3的结构指针 *ppDB 为数据库连接句柄。如果数据库被成功打开(和/或 创建), 函数返回 SQLITE_OK;否则返回一个错误码, 可以通过* sqlite3_errmsg()* 查看错误原因.。出错,则只可能是 SQLite 无法为 SQLite 对象分配内存空间, 此时将返回 NULL。

关闭数据库

1.原型:

int sqlite3_close(
       sqlite3* pDB /* 由 sqlite3_open 或基相关的函数打开的 SQLite 对象句柄 */
    );

2.说明:
该函数用来关闭 sqlite3 对象。返回 SQLITE_OK 表示对象被成功关闭,以及所有相关的资源被成功回收。应用程序必须在关闭之前 “完成(finalize)” 所有的 “预编译语句(prepared statements)”, 并且关闭所有的 “二进制句柄绑定(BLOB handle)”, 如果在关闭时还有未完成的预编译语句或二进制句柄, 那么函数返回 SQLITE_BUSY(5)。

错误处理

原型1:

const char *sqlite3_errmsg(
    sqlite3* pDB    /* SQLite3 数据库句柄 */
);

说明1:
该函数返回与pDB数据库指针相关的错误信息,下次调用会覆盖。

原型2:

int sqlite3_errcode(
    sqlite3* pDB    /* SQLite3 数据库句柄 */
)

说明2:
该函数返回最近一次调用 sqlite3_ API时产生的错误码。

示例一:

/*************************************************************************
    > File Name: example1.c
    > Author: AnSwEr
    > Mail: 1045837697@qq.com
    > Created Time: 2015年08月29日 星期六 14时17分21秒
 ************************************************************************/

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

int main(void)
{
    char *filename = "./first.db";
    sqlite3 *pDB = NULL;
    int ret = 0;

    ret = sqlite3_open(filename,&pDB);
    if(ret != SQLITE_OK)
    {
        fprintf(stderr,"%s\n",sqlite3_errmsg(pDB));
        exit(EXIT_FAILURE);
    }

    /*do something*/
    printf("open successfully!\n");

    if(pDB != NULL)
    {
        sqlite3_close(pDB);
        pDB = NULL;
    }

    printf("close successfully!\n");

    return 0;
}

示例一实现打开和关闭操作。

执行sql语句

原型:

int sqlite3_exec(
    sqlite3* pDB,        /* sqlite3句柄 */
    const char* sql,    /* 被执行的 SQL 语句 */
    int (*callback)(void*,int,char**,char**),  /* 执行/查询回调函数 */
    void* pvoid,    /* 传递给回调函数的第一个参数 */
    char**errmsg    /* 错误输出信息 */
);

说明:
当回调函数不为 NULL, 则它对每一个行查询结果都会调用该回调函数;如果没有回调函数被指定, sqlite3_exec() 只是简单地忽略查询结果。
如果回调函数返回非零,sqlite3_exec() 立即中断查询,并且不再执行后续的 SQL 语句,也不再调用回调函数, sqlite3_exec() 将返回 SQLITE_ABORT 结束执行。
当发生错误时, 执行将中断。如果 errmsg 参数不为空,错误信息将会被写入(errmsg sqlite3_malloc() 分配内存空间,由sqlite3_free() 释放该内存空间)。如果 errmsg 参数不为 NULL, 并且没有错误发生, errmsg 被设置为 NULL
通常情况下callbackselect操作中会使用到,如果不需要回调函数。第三第四个参数设为NULL

回调函数原型:

int callback(
    void *params,  /*params是sqlite3_exec传入的第四个参数*/
    int column_size,  /*column_size是结果字段的个数*/
    char **column_value,  /*column_value是返回记录的一位字符数组指针*/
    char **column_name  /*column_name是结果字段的名称*/
);

示例二

/*************************************************************************
    > File Name: example2.c
    > Author: AnSwEr
    > Mail: 1045837697@qq.com
    > Created Time: 2015年08月29日 星期六 20时11分06秒
 ************************************************************************/

/*
 * 查询数据库
 */
#include<stdio.h>
#include<stdlib.h>
#include"sqlite3.h"

static print_info(void *params,int column_size,char **column_value,char **column_name)
{
    int i;

    for(i=0;i<column_size;i++)
        printf("\t%s",column_value[i]);
    printf("\n");

    return 0;
}

int main(void)
{
    char *filename = "./first.db";
    sqlite3 *pDB = NULL;
    int ret = 0;

    /*open*/
    ret = sqlite3_open(filename,&pDB);
    if(ret != SQLITE_OK)
    {
        fprintf(stderr,"%s\n",sqlite3_errmsg(pDB));
        exit(EXIT_FAILURE);
    }

    /*select*/
    char *errmsg = 0;
    ret = sqlite3_exec(pDB,"select * from stutable",print_info,NULL,&errmsg);
    if(ret != SQLITE_OK)
        fprintf(stderr,"select error:%s\n",errmsg);

    sqlite3_free(errmsg);

    /*close*/
    if(pDB != NULL)
    {
        sqlite3_close(pDB);
        pDB = NULL;
    }

    return 0;
}

示例二执行使用回调函数的select语句。此外,还有不使用回调函数的select语句(使用sqlite3_get_table,此函数是sqlite3_exec的包装)。 不过个人感觉还是使用回调函数好,这样代码可看性强,更整洁。

sqlite3_get_table原型:

int sqlite3_get_table(
  sqlite3 *db,          /* An open database */
  const char *zSql,     /* SQL to be evaluated */
  char ***pazResult,    /* Results of the query */
  int *pnRow,           /* Number of result rows written here */
  int *pnColumn,        /* Number of result columns written here */
  char **pzErrmsg       /* Error msg written here */
);
void sqlite3_free_table(char **result);

/*
db是sqlite3的句柄
zSql是要执行的sql语句
pazResult是执行查询操作的返回结果集
pnRow是记录的行数
pnColumn是记录的字段个数
pzErrmsg是错误信息

pazResult是一个(pnRow+1)*pnColumn结果集的字符串数组,其中前pnColumn个结果是字段的名称,后pnRow行记录是真实的字段值,如果某个字段为空,则对应值为NULL。

这里贴一段网上查到的不使用回调函数的select示例:

char **dbresult; int j,nrow,ncolumn,index;
//select table
    ret = sqlite3_get_table(db,"select * from t",&dbresult,&nrow,&ncolumn,&errmsg);
    if(ret == SQLITE_OK){
        printf("query %i records.\n",nrow);
        index=ncolumn;
        for(i=0;i<nrow;i++){
            printf("[%2i]",i);
            for(j=0;j<ncolumn;j++){
                printf(" %s",dbresult[index]);
                index++;
            }
            printf("\n");
        }
    }
    sqlite3_free_table(dbresult);

示例三

/*************************************************************************
    > File Name: example3.c
    > Author: AnSwEr
    > Mail: 1045837697@qq.com
    > Created Time: 2015年08月29日 星期六 20时44分10秒
 ************************************************************************/

/*
 * 表的创建与删除,数据的插入,更新与删除。
 */

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

static print_info(void *params,int column_size,char **column_value,char **column_name)
{
    int i;

    for(i=0;i<column_size;i++)
        printf("\t%s",column_value[i]);
    printf("\n");

    return 0;
}

int main(void)
{
    char *filename = "./first.db";
    sqlite3 *pDB = NULL;
    int ret = 0;

    /*open*/
    ret = sqlite3_open(filename,&pDB);
    if(ret != SQLITE_OK)
    {
        fprintf(stderr,"%s\n",sqlite3_errmsg(pDB));
        exit(EXIT_FAILURE);
    }

    /*创建表*/
    const char *create_table = "create table t(id int primary key,name vachar(128))";
    char *errmsg = 0;
    ret = sqlite3_exec(pDB,create_table,NULL,NULL,&errmsg);
    if(ret != SQLITE_OK)
        fprintf(stderr,"create table error:%s\n",errmsg);
    sqlite3_free(errmsg);

    /*插入数据*/
    const char *insert_data = "insert into t(id,name) values(1,‘answer‘)";
    ret = sqlite3_exec(pDB,insert_data,NULL,NULL,&errmsg);
    if(ret != SQLITE_OK)
        fprintf(stderr,"insert data error:%s\n",errmsg);

    /*查询表中数据*/
    ret = sqlite3_exec(pDB,"select * from t",print_info,NULL,&errmsg);
    if(ret != SQLITE_OK)
        fprintf(stderr,"select error:%s\n",errmsg);
    printf("\n");

    /*更新表中数据*/
    const char *update_data = "update t set name=‘jack‘ where id=1";
    ret = sqlite3_exec(pDB,update_data,NULL,NULL,&errmsg);
    if(ret != SQLITE_OK)
        fprintf(stderr,"update_data error:%s\n",errmsg);

    /*查询表中数据*/
    ret = sqlite3_exec(pDB,"select * from t",print_info,NULL,&errmsg);
    if(ret != SQLITE_OK)
        fprintf(stderr,"select error:%s\n",errmsg);
    printf("\n");

    /*删除数据*/
    const char *delete_data = "delete from t where id = 1";
    ret = sqlite3_exec(pDB,delete_data,NULL,NULL,&errmsg);
    if(ret != SQLITE_OK)
        fprintf(stderr,"delete data error:%s\n",errmsg);

    /*查询受上次操作影响的记录数*/
    printf("delete data records:%i\n",sqlite3_changes(pDB));
    printf("\n");

    /*删除表*/
    const char *drop_table = "drop table if exists t";
    ret = sqlite3_exec(pDB,drop_table,NULL,NULL,&errmsg);
    if(ret != SQLITE_OK)
        fprintf(stderr,"drop table error:%s\n",errmsg);

    /*close*/
    if(pDB != NULL)
    {
        sqlite3_close(pDB);
        pDB = NULL;
    }

    return 0;
}

示例三演示创建\删除表,数据的插入、更新与删除。

预编译操作

注意:sqlite3_exec中已经封装了预编译操作,直接使用即可,预编译操作只需稍作了解。

网上查了很多sqlite的预编译操作的例子,比较复杂,大致可以分为以下几个步骤:
1. 通过sqlite3_prepare创建一个sqlite3_stmt对象
2. 通过sqlite3_bind_*()绑定预编译字段的值
3. 通过sqlite3_step()执行SQL语句
4. 通过sqlite3_reset()重置预编译语句,重复操作2多次
5. 通过sqlite3_finalize()销毁资源

下面依次来看看这些函数。

sqlite3_prepare原型:

int sqlite3_prepare(
    sqlite3* pDB,            /* 成功打开的数据库句柄 */
    const char* sql,        /* UTF8编码的 SQL 语句 */
    int nbytes,                /* 参数 sql 的字节数, 包含 ‘\0‘ */
    sqlite3_stmt** ppStmt,    /* 输出:预编译语句句柄 */
    const char** pszTail    /* 输出:指向 sql 语句中未使用的部分 */
);

说明:
如果nbytes小于0, sql 语句则以第一个 ‘\0’终结。如果它非负,,则为读取的最大长度.。当nbytes 大于 0 时,则读取指定长度,如果’\0’先被读到,则以’\0’结束。如果用户知道被传入的 sql 语句是以 ‘\0’ 结尾的,那么有一个更好的做法是:把nbytes的值设为该字符串的长度(包含’\0’),这样可以避免 SQLite 复制该字符串的一份拷贝, 以提高程序的效率。
如果 pszTail 不为 NULL, 则 *pszTail 指向 sql 中第一个被传入的 SQL 语句的结尾。该函数只编译 sql 的第一个语句, 所以 *pszTail 指向的内容则是未被编译的。
*ppStmt 指向一条可以被 sqlie3_step() 函数使用的预编译语句.。如果有错误发生, pszStmt 的值为*NULL
调用者应该使用 sqlite3_finalize() 删掉被预编译的语句。
如果函数成功, 返回 SQLITE_OK, 否则返回一个错误码。

sqlite3_bind_*有多种形式,分别对应不同的数据类型:

int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
int sqlite3_bind_double(sqlite3_stmt*, int, double);
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
int sqlite3_bind_null(sqlite3_stmt*, int);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);

预编译SQL语句中可以包含如下几种形式:

?
?NNN
:VVV
@VVV
$VVV

NNN代表数字,VVV代表字符串.
如果是?或者?NNN,那么可以直接sqlite3_bind_*()进行操作,如果是字符串,还需要通过sqlite3_bind_parameter_index()获取对应的index,然后再调用sqlite3_bind_*()操作。这通常用于构造不定条件的SQL语句(动态SQL语句)。

int sqlite3_step原型:

int sqlite3_step(
    sqlite3_stmt* ppStmt    /* 一条被预编译的 sql 语句 */
);

说明:
当一条语句被 sqlite3_prepare() 或其相关的函数预编译后, sqlite3_step() 必须被调用一次或多次来评估该预编译语句。
该函数的详细行为依赖于由 sqlite3_prepare()(或其相关的函数) 产生的是一条怎样的预编译语句。

返回值:
SQLITE_BUSY:忙碌. 数据库引擎无法锁定数据去完成其工作。但可以多次尝试。
SQLITE_DONE:完成. sql 语句已经被成功地执行。在调用 sqlite_reset() 之前, 当前预编译的语句不应该被 sqlite3_step() 再次调用。
SQLITE_ROW:查询时产生了结果。此时可以通过相关的”数据访问函数(column access functions)”来取得数据. sqlite3_step() 的再一次调用将取得下一条查询结果。
SQLITE_ERROR:发生了错误。 此时可以通过 sqlite3_errmmsg() 取得相关的错误信息. sqlite3_step() 不能被再次调用。
SQLITE_MISUSE:不正确的库的使用. 该函数使用不当。

sqlite3_finalize原型:

int sqlite3_finalize(
    sqlite3_stmt* pStmt    /* 被预编译的语句 */
);

说明:
该函数用来删除一条被预编译的 sql 语句。

预编译实现代码:

    int i = 0;
    sqlite3_stmt *stmt;
    char ca[255];

    //预编译操作
    sqlite3_prepare_v2(db,"insert into t(id,msg) values(?,?)",-1,&stmt,0);
    for(i=10;i<20;i++){
        sprintf(ca,"HELLO#%i",i);
        sqlite3_bind_int(stmt,1,i);
        sqlite3_bind_text(stmt,2,ca,strlen(ca),NULL);
        sqlite3_step(stmt);
        sqlite3_reset(stmt);
    }
    sqlite3_finalize(stmt);
    stmt = NULL;

总结

上文列出的是一些最基本精简的C语言API,sqlite为C语言一共提供了200多个API。不过,上述这些API对一般的开发者而言已经足够了,如果你还有更多的需求,那就请查阅前言中给出的源代码文件(sqlite3.c,sqlite3.h)。

反馈与建议

版权声明:本文为博主原创文章,未经博主允许不得转载。

Linux平台上SQLite数据库教程(二)——C语言API介绍

标签:sqlite   linux-c   c语言   

原文地址:http://blog.csdn.net/u011192270/article/details/48086961

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!