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不是答案的專欄