http://blog.csdn.net/u011192270/article/details/48086961
前言:本文将介绍几个基本的SQLite3数据库的C语言API接口,主要用到两个文件:sqlite3.c、sqlite3.h。源码地址:https://github.com/AnSwErYWJ/SQLite。
打开数据库
1.原型:
int sqlite3_open(const char* filename, sqlite3** ppDB
);;
2.说明:
参数filename为指定打开的数据库, sqlite3的结构指针 *ppDB 为数据库连接句柄。如果数据库被成功打开(和/或 创建), 函数返回 SQLITE_OK;否则返回一个错误码, 可以通过* sqlite3_errmsg()* 查看错误原因.。出错,则只可能是 SQLite 无法为 SQLite 对象分配内存空间, 此时将返回 NULL。
关闭数据库
1.原型:
int sqlite3_close(sqlite3* pDB );
2.说明:
该函数用来关闭 sqlite3 对象。返回 SQLITE_OK 表示对象被成功关闭,以及所有相关的资源被成功回收。应用程序必须在关闭之前 “完成(finalize)” 所有的 “预编译语句(prepared statements)”, 并且关闭所有的 “二进制句柄绑定(BLOB handle)”, 如果在关闭时还有未完成的预编译语句或二进制句柄, 那么函数返回 SQLITE_BUSY(5)。
错误处理
原型1:
const char *sqlite3_errmsg(sqlite3* pDB
);
说明1:
该函数返回与pDB数据库指针相关的错误信息,下次调用会覆盖。
原型2:
int sqlite3_errcode(sqlite3* pDB
)
说明2:
该函数返回最近一次调用 sqlite3_ API时产生的错误码。
示例一:
/*************************************************************************
> File Name: example1.c
> Author: AnSwEr
> Mail: 1045837697@qq.com
> Created Time: 2015年08月29日 星期六 14时17分21秒************************************************************************/
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
示例一实现打开和关闭操作。
执行sql语句
原型:
int sqlite3_exec(sqlite3* pDB, const char* 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。
通常情况下callback在select操作中会使用到,如果不需要回调函数。第三第四个参数设为NULL。
回调函数原型:
int callback(void *params, int column_size, char **column_value, char **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;ret = sqlite3_open(filename,&pDB);if(ret != SQLITE_OK){fprintf(stderr,"%s\n",sqlite3_errmsg(pDB));exit(EXIT_FAILURE);}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);if(pDB != NULL){sqlite3_close(pDB);pDB = NULL;}return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
示例二执行使用回调函数的select语句。此外,还有不使用回调函数的select语句(使用sqlite3_get_table,此函数是sqlite3_exec的包装)。 不过个人感觉还是使用回调函数好,这样代码可看性强,更整洁。
sqlite3_get_table原型:
int sqlite3_get_table(sqlite3 *db, const char *zSql, char ***pazResult, int *pnRow, int *pnColumn, char **pzErrmsg
);
void sqlite3_free_table(char **result);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
这里贴一段网上查到的不使用回调函数的select示例:
char **dbresult; int j,nrow,ncolumn,index;
//select tableret = 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);
示例三
#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;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);if(pDB != NULL){sqlite3_close(pDB);pDB = NULL;}return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
示例三演示创建\删除表,数据的插入、更新与删除。
预编译操作
注意: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, int nbytes, sqlite3_stmt** ppStmt, const char** pszTail
);
说明:
如果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
);
说明:
当一条语句被 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)。
反馈与建议
- 微博:@AnSwEr不是答案
- github:AnSwErYWJ
- 博客:AnSwEr不是答案的专栏