sqlite c 语言客户端编程接口抽象

前端之家收集整理的这篇文章主要介绍了sqlite c 语言客户端编程接口抽象前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

csdn lidp 转载注明出处


封装几个sqlite3 数据库接口,通过利用sqlite3提供的api实现数据库的打开,关闭,创建表,添加删除字段,基于事务实现。


数据库接口为我在google code上建立的的开源项目spider-tool的一部分,

关于spider-tool,欢迎访问google code.

https://spider-tool.googlecode.com


sqlite3 C语言api接口参照这里;

http://www.sqlite.org/c3ref/intro.html

http://wenku.baidu.com/view/9b0c2619964bcf84b9d57b46.html

http://wenku.baidu.com/view/65005486b9d528ea81c7794b.html


调用sqlite3_prepare()将sql语句编译为sqlite内部一个结构体(sqlite3_stmt). 该结构体中包含了将要执行的的 sql语句的信息.
** 如果需要传入参数,在sql语句中用'?'作为占位符,再调用sqlite3_bind_XXX()函数将对应的参数传入.
** 调用sqlite3_step(),这时候sql语句才真正执行.注意该函数的返回值,sqlITE_DONE和sqlITE_ROW都是表示执行成功,不同的是sqlITE_DONE表示没有查询结果,象UPDATE,INSERT这些sql语句都是返回sqlITE_DONE,SELECT查询语句在 查询结果不为空的时候返回sqlITE_ROW,在查询结果为空的时候返回sqlITE_DONE.
** 每次调用sqlite3_step()的时候,只返回一行数据,使用sqlite3_column_XXX()函数来取出这些数据.要取出全部的数据需要 反复调用sqlite3_step(). (注意,在bind参数的时候,参数列表的index从1开始,而取出数据的时候,列的index是从0开始).
** 在sql语句使用完了之后要调用sqlite3_finalize()来释放stmt占用的内存.该内存是在sqlite3_prepare()时分配的.
** 如果sql语句要重复使用,可以调用sqlite3_reset()来清楚已经绑定的参数.


db.h

/*
 * Spider -- An open source C language toolkit.
 *
 * Copyright (C) 2011,Inc.
 *
 * lidp <openser@yeah.net>
 *
 * This program is free software,distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */
#ifndef _SPIDER_INTERNAL_DB_H
#define _SPIDER_INTERNAL_DB_H

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

struct spd_db_entry {
	struct spd_db_entry *next;
	char *key;
	char data[0];
};

/*!\brief Get key value specified by family/key */
int spd_db_get(const char *table,const char *key,char *buf,int len);

/*!\brief Store value addressed by family/key */
int spd_db_put(const char * table,const char *buf);

/*!\brief Delete entry in db */
int spd_db_del(const char *table,const char *key);

/*!\brief Delete one or more entries in spddb
 * If both parameters are NULL,the entire database will be purged.  If
 * only keytree is NULL,all entries within the family will be purged.
 * It is an error for keytree to have a value when family is NULL.
 *
 * \retval -1 An error occurred
 * \retval >= 0 Number of records deleted
 */
int spd_db_deltree(const char *table,const char *key);

/*!\brief Get a list of values within the spddb tree
 * If family is specified,only those keys will be returned.  If keytree
 * is specified,subkeys are expected to exist (separated from the key with
 * a slash).  If subkeys do not exist and keytree is specified,the tree will
 * consist of either a single entry or NULL will be returned.
 *
 * Resulting tree should be freed by passing the return value to spd_db_freetree()
 * when usage is concluded.
 */
struct spd_db_entry *spd_db_gettree(const char *table,const char *key);

/*!\brief Free structure created by spd_db_gettree() */
void spd_db_freetree(struct spd_db_entry *entry);

/* init db engine at start time */
int spddb_init(void);
void spddb_uninit(void);
	
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif




db.c

/*
 * Spider -- An open source C language toolkit.
 *
 * Copyright (C) 2011,distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <signal.h>
 #include <dirent.h>
 #include <sqlite3.h>

 #include "logger.h"
 #include "utils.h"
 #include "thread.h"
 #include "lock.h"
 #include "internal_db.h"
 #include "strings.h"
 #include "test_engine.h"
 
/*
  * sqlite c interface api
  * http://www.sqlite.org/c3ref/open.html
  */

SPD_MUTEX_DEFINE_STATIC(dblock);
static spd_cond_t dbcond;
static pthread_t  dbsync_thread;
static int doexit;
static sqlite3 *spd_db;
const char* spddb_dir = "/tmp/spddb";


#define SPD_DB_STATEMENT_DEFINE(stmt,sql) static sqlite3_stmt *stmt; \
	const char stmt##_sql[] = sql;

SPD_DB_STATEMENT_DEFINE(put_stmt,"INSERT OR REPLACE INTO spd_db (key,value) VALUES (?,?)")
SPD_DB_STATEMENT_DEFINE(get_stmt,"SELECT value FROM spd_db WHERE key =?")
SPD_DB_STATEMENT_DEFINE(del_stmt,"DELETE FROM spd_db WHERE key=?")
SPD_DB_STATEMENT_DEFINE(deltree_stmt,"DELETE FROM spd_db WHERE key || '/' LIKE ? || '/' || '%'")
SPD_DB_STATEMENT_DEFINE(deltree_all_stmt,"DELETE FROM spd_db")
SPD_DB_STATEMENT_DEFINE(gettree_stmt,"SELECT key,value FROM spd_db WHERE key || '/' LIKE ? || '/' || '%' ORDER BY key")
SPD_DB_STATEMENT_DEFINE(gettree_all_stmt,value FROM spd_db ORDER BY key")
SPD_DB_STATEMENT_DEFINE(create_spd_db_stmt,"CREATE TABLE IF NOT EXISTS spd_db(key VARCHAR(256),value VARCHAR(256),PRIMARY KEY(key))");

static int db_open()
{
	char *dbname;
	if(!(dbname = alloca(strlen(spddb_dir) + sizeof(".db")))) {
		spd_log(LOG_ERROR,"alloca Failed\n");
		return -1;
	}	

	strcpy(dbname,spddb_dir);
	strcat(dbname,".db");

	spd_mutex_lock(&dblock);
	if(sqlite3_open(dbname,&spd_db) != sqlITE_OK) {
		spd_log(LOG_ERROR,"Failed open db '%s' %s\n",dbname,sqlite3_errmsg(spd_db));
		spd_mutex_unlock(&dblock);
		return -1;
	}
	spd_mutex_unlock(&dblock);

}

/*
  * sync db signal,must lock db first.
  */
static void do_dbsync()
{
	spd_cond_signal(&dbcond);
}

static int init_stmt(sqlite3_stmt **stmt,const char *sql,size_t len)
{
	spd_mutex_lock(&dblock);
	if(sqlite3_prepare(spd_db,sql,len,stmt,NULL) != sqlITE_OK) {
		spd_log(LOG_WARNING,"could not prepare statement '%s': %s\n",sqlite3_errmsg(spd_db));
		spd_mutex_unlock(&dblock);
		return -1;
	}
	spd_mutex_unlock(&dblock);

	return 0;
}

static int db_create()
{
	int ret = 0;
	
	if(!create_spd_db_stmt) {
		init_stmt(&create_spd_db_stmt,create_spd_db_stmt_sql,sizeof(create_spd_db_stmt_sql));
	}

	spd_mutex_lock(&dblock);
	if(sqlite3_step(create_spd_db_stmt) != sqlITE_DONE) {
		spd_log(LOG_WARNING,"Couldnot create spd db table: %s\n",sqlite3_errmsg(spd_db));
		ret = -1;
	}

	sqlite3_reset(create_spd_db_stmt);
	do_dbsync();
	spd_mutex_unlock(&dblock);

	return ret;
}

/*
 * init stmt on start up for performance.
 */
static int db_init_statements()
{
	return init_stmt(&get_stmt,get_stmt_sql,sizeof(get_stmt_sql))
		|| init_stmt(&del_stmt,del_stmt_sql,sizeof(del_stmt_sql))
		|| init_stmt(&deltree_stmt,deltree_stmt_sql,sizeof(deltree_stmt_sql))
		|| init_stmt(&deltree_all_stmt,deltree_all_stmt_sql,sizeof(deltree_all_stmt_sql))
		|| init_stmt(&gettree_stmt,gettree_stmt_sql,sizeof(gettree_stmt_sql))
		|| init_stmt(&gettree_all_stmt,gettree_all_stmt_sql,sizeof(gettree_all_stmt_sql))
		|| init_stmt(&put_stmt,put_stmt_sql,sizeof(put_stmt_sql));
}



/* init db engine,open,create and init stmt */
static int db_init()
{
	if(spd_db)
		return 0;

	if(db_open() || db_create() || db_init_statements())
		return -1;

	return 0;
}

static void spd_db_close(sqlite3 *db)
{
	sqlite3_close(db);
}

/*
  * perform clean up resource.
  */
void spddb_uninit(void)
{
	spd_log(LOG_NOTICE,"uninit db \n");
	doexit = 1;
	spd_mutex_lock(&dblock);
	do_dbsync();
	spd_mutex_unlock(&dblock);
	
	pthread_join(dbsync_thread,NULL);
	spd_mutex_lock(&dblock);
	spd_db_close(spd_db);
	spd_mutex_unlock(&dblock);

	spd_mutex_destroy(&dblock);
	spd_cond_destroy(&dbcond);
	spd_log(LOG_NOTICE,"uninit db end .\n");
}

int spd_db_get(const char * table,const char * key,char * buf,int len)
{
	const unsigned char *result;
	char fullkey[256];
	size_t fullkey_len;
	int res = 0;

	if(strlen(table) + strlen(key) + 2 > sizeof(fullkey) -1) {
		spd_log(LOG_WARNING,"table and key too large lengh\n");
		return -1;
	}

	fullkey_len = snprintf(fullkey,sizeof(fullkey),"/%s/%s",table,key);

	spd_mutex_lock(&dblock);

	if(sqlite3_bind_text(get_stmt,1,fullkey,fullkey_len,sqlITE_STATIC) != sqlITE_OK) {
		spd_log(LOG_WARNING,"Couldnot bind key to stmt:%s\n",sqlite3_errmsg(spd_db));
		res = -1;
	} else if(sqlite3_step(get_stmt) != sqlITE_ROW) {
		spd_log(LOG_WARNING,"Unable to find key '%s' in table '%s' \n",key,table);
		res = -1;
	} else if (!(result = sqlite3_column_text(get_stmt,0))) {
		spd_log(LOG_WARNING,"Couldn't get value\n");
		res = -1;
	} else {
		strncpy(buf,(const char *) result,len);
	}
	sqlite3_reset(get_stmt);
	spd_mutex_unlock(&dblock);

	return res;
}

int spd_db_put(const char * table,const char * buf)
{
	char fullkey[256];
	size_t fullkey_len;
	int res = 0;

	if(strlen(table) + strlen(key) + 2 > sizeof(fullkey)) {
		spd_log(LOG_WARNING,key);

	spd_mutex_lock(&dblock);
	
	if(sqlite3_bind_text(put_stmt,"Could not bind key to stmt : %s\n",sqlite3_errmsg(spd_db));
		res = -1;
	} else if(sqlite3_bind_text(put_stmt,2,buf,-1,"Could not bind value to stmt: %s\n",sqlite3_errmsg(spd_db));
		res = -1;
	} else if(sqlite3_step(put_stmt) != sqlITE_DONE) {
		spd_log(LOG_WARNING,"Could not execute statement: %s\n",sqlite3_errmsg(spd_db));
		res = -1;
	}
	
	/* make us reused */
	sqlite3_reset(put_stmt);
	do_dbsync();
	spd_mutex_unlock(&dblock);

	return res;
}

int spd_db_del(const char * table,const char * key)
{
	char fullkey[256];
	size_t fullkey_len;
	int res = 0;

	if(strlen(table) + strlen(key) + 2 > sizeof(fullkey)) {
		spd_log(LOG_WARNING,key);

	spd_mutex_lock(&dblock);
	if(sqlite3_bind_text(del_stmt,sqlite3_errmsg(spd_db));
		res = -1;
	} else if(sqlite3_step(del_stmt) != sqlITE_DONE) {
		spd_log(LOG_WARNING,"Unable to find key '%s' in table '%s'\n",table);
		res = -1;
	}

	sqlite3_reset(del_stmt);

	do_dbsync();
	spd_mutex_unlock(&dblock);

	return res;
}

struct spd_db_entry * spd_db_gettree(const char * table,const char * key)
{
	char prefix[256];
	sqlite3_stmt *stmt = gettree_stmt;
	struct spd_db_entry *cur,*last = NULL,*ret = NULL;

	if(!spd_strlen_zero(table)) {
		if(!spd_strlen_zero(table)) {
			snprintf(prefix,sizeof(prefix),key);
		} else {
			snprintf(prefix,"/%s",table);
		}
	} else {
		prefix[0] = '\0';
		stmt = gettree_stmt;
	}

	spd_mutex_lock(&dblock);
	if(!spd_strlen_zero(prefix) && (sqlite3_bind_text(stmt,prefix,sqlITE_STATIC) != sqlITE_OK)) {
		spd_log(LOG_WARNING,"Could bind %s to stmt: %s\n",sqlite3_errmsg(spd_db));
		sqlite3_reset(stmt);
		spd_mutex_unlock(&dblock);
		return NULL;
	}

	while(sqlite3_step(stmt) == sqlITE_ROW) {
		const char *key_s,*value_s;
		if (!(key_s = (const char *) sqlite3_column_text(stmt,0))) {
			break;
		}
		if (!(value_s = (const char *) sqlite3_column_text(stmt,1))) {
			break;
		}

		if(!(cur = spd_malloc(sizeof(*cur) + strlen(key_s) + strlen(value_s) + 2))) {
			break;
		}

		cur->next = NULL;
		cur->key = cur->data + strlen(value_s) + 1;
		strcpy(cur->data,value_s);
		strcpy(cur->key,key_s);
		if(last) {
			last->next = cur;
		} else {
			ret = cur;
		}
		last = cur;
	}

	sqlite3_reset(stmt);
	spd_mutex_unlock(&dblock);

	return ret;
}

int spd_db_deltree(const char * table,const char * key)
{
	sqlite3_stmt *stmt = deltree_stmt;
	char prefix[256];
	int res = 0;

	if (!spd_strlen_zero(table)) {
		if (!spd_strlen_zero(key)) {
			/* Family and key tree */
			snprintf(prefix,key);
		} else {
			/* Family only */
			snprintf(prefix,table);
		}
	} else {
		prefix[0] = '\0';
		stmt = deltree_all_stmt;
	}

	spd_mutex_lock(&dblock);
	if (!spd_strlen_zero(prefix) && (sqlite3_bind_text(stmt,sqlite3_errmsg(spd_db));
		res = -1;
	} else if (sqlite3_step(stmt) != sqlITE_DONE) {
		spd_log(LOG_WARNING,"Couldn't execute stmt: %s\n",sqlite3_errmsg(spd_db));
		res = -1;
	}
	res = sqlite3_changes(spd_db);
	sqlite3_reset(stmt);
	do_dbsync();
	spd_mutex_unlock(&dblock);

	return res;
}

void spd_db_freetree(struct spd_db_entry * entry)
{
	struct  spd_db_entry *last;

	while(entry) {
		last = entry;
		entry = entry->next;
		spd_safe_free(last);
	}
}

static int db_do_transaction(const char *sql,int(*callback)(void *,int,char **,char **),void *arg)
{
	char *errmsg = NULL;
	int ret = 0;
    
	sqlite3_exec(spd_db,callback,arg,&errmsg);
	if(errmsg) {
		spd_log(LOG_WARNING,"Error excuting sql :%s\n",errmsg);
		sqlite3_free(errmsg);
		ret = -1;
	}

	return ret;
}

static int spd_db_begin_transaction()
{
	return db_do_transaction("BEGIN TRANSACTION",NULL,NULL);
}
	 
static int spd_db_commite_trancaction()
{
	return db_do_transaction("COMMIT",NULL);
}

static int spd_db_rollback_transaction()
{
	db_do_transaction("ROLLBACK",NULL);
}

static void *dbsync_thread_loop(void *data)
{
	spd_mutex_lock(&dblock);
	spd_db_begin_transaction();
	//spd_log(LOG_NOTICE,"db sync thread loop\n");

	for(;;) {
		//spd_log(LOG_NOTICE,"wait sync cond \n");
		spd_cond_wait(&dbcond,&dblock);
		//spd_log(LOG_NOTICE,"get sync cond \n");
		if(spd_db_commite_trancaction()) {
			spd_db_rollback_transaction();
		}
		if(doexit) {
			spd_mutex_unlock(&dblock);
			break;
		}

		spd_db_begin_transaction();
		spd_mutex_unlock(&dblock);
		sleep(1);
		spd_mutex_lock(&dblock);
		if(doexit) {
			spd_mutex_unlock(&dblock);
			break;
		}
	}

	return NULL;
}

int spddb_init(void)
{
	spd_log(LOG_NOTICE,"start init db engine...\n");
	if(db_init()) {
		spd_log(LOG_ERROR,"spd db init Failed \n");
		return -1;
	}

	spd_cond_init(&dbcond,NULL);
	if(spd_pthread_create_background(&dbsync_thread,dbsync_thread_loop,NULL)) {
		spd_log(LOG_ERROR,"Failed to start db thread. \n");
		return -1;
	}

	spd_log(LOG_NOTICE,"end init db engine...\n");
	return 0;
 }


const char large_name[] = "fjlkdsj";

enum {
	FAMILY = 0,KEY = 1,VALUE = 2,};

SPD_TEST_INIT(test_db)
{
	int res = TEST_RESULT_PASS;
	int i;
	char buf[sizeof(large_name)] = {0,};
	const char *inputs[][3] = {
		{"family","key","value"},{"dbtest","a","b"},"a"},"b",};

 	switch(type) {
		case SPD_TEST_CMD_INIT:
			record->name = "test_db";
			record->category = "/spider/db/";
			record->description = "spd db get|put|del unit test";
			
			return TEST_RESULT_NOT_RUN;
			
		case SPD_TEST_CMD_RUN:
			break;
	}
	
	for(i = 0; i < ARRAY_LEN(inputs); i++) {

		if(spd_db_put(inputs[i][FAMILY],inputs[i][KEY],inputs[i][VALUE])) {
			spd_log(LOG_ERROR,"test Failed in db put %s : %s : %s : \n",inputs[i][FAMILY],inputs[i][VALUE]);
			spd_test_update_state(test,inputs[i][VALUE]);
			res = TEST_RESULT_Failed;
		} 

		if(spd_db_get(inputs[i][FAMILY],sizeof(buf))) {
			spd_log(LOG_ERROR,inputs[i][VALUE]);
			res = TEST_RESULT_Failed;
		} else if (strcasecmp(inputs[i][VALUE],buf)) {
			spd_log(LOG_ERROR,"test Failed in db get,this is not match value,expect %s but %s \n",inputs[i][VALUE]);
			res = TEST_RESULT_Failed;
		} else {
			//spd_log(LOG_NOTICE,"get success %s %s %s \n",buf);
		}
		
		if(spd_db_del(inputs[i][FAMILY],inputs[i][KEY])) {
			spd_log(LOG_ERROR,"test Failed in db del %s : %s : \n",inputs[i][KEY]);
			spd_test_update_state(test,inputs[i][VALUE]);
			res = TEST_RESULT_Failed;
		}
		
	}

	return res;
}

int test_spddb()
{

	SPD_TEST_REGISTER(test_db);	
	SPD_TEST_RUN("test_db",NULL);
	SPD_TEST_REPORT("test_db","/tmp/spddb_test");
	SPD_TEST_UNREGISTER(test_db);

	return 0;
}
原文链接:https://www.f2er.com/sqlite/202159.html

猜你在找的Sqlite相关文章