說明:經過sqlite3_get_table查詢獲得的結果,其結構是:第一行是列名,隨後的行纔是值。遍歷的方式和二維數組相同。html
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
#include "test.h"
int main(int argc, char **argv)
{
sqlite3 *db;
char **dbResult;
char *errmsg;
int nRow, nColumn;
int index=0;
int i, j, rc;linux
if( argc!=2 )
{
fprintf(stderr, "Usage: %s DATABASE \n", argv[0]);
exit(1);
}web
rc = sqlite3_open(argv[1], &db);
if( rc != SQLITE_OK )
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}sql
rc = sqlite3_get_table( db, "select * from users", &dbResult, &nRow, &nColumn, &errmsg);
if (rc == SQLITE_OK)
{
printf("表格共%d 記錄!\n", nRow);
printf("表格共%d 列!\n", nColumn);
// 前兩個字段爲字段名 field0, field1, row[0][0], row[0][1], row[1][0], row[1][1] ... ... ....
// 是一維數組,不是二維數組,反正記着第0,第1列的值爲字段名,而後纔是字段值;
printf( "字段名|字段值\n");
printf( "%s | %s\n", dbResult[0], dbResult[1]);
printf("--------------------------------\n");
index = nColumn; //字段值從index開始呀
for( i = 0; i < nRow ; i++ )
{
for( j = 0 ; j < nColumn; j++ )
{
printf( "%-5s ",dbResult[index++]);
}
printf("\n");
}
printf("--------------------------------\n");
}數據庫
sqlite3_close(db);
return 0;
}
/* test.h是爲空的 */express
makefile以下:
all: test
CC=gcc -g -Wall
clean:
@rm -rf *.o
test: test.o
$(CC) -ldl -lsqlite3 -o test test.o
test.o: test.c test.h
$(CC) -c test.c
red hat as4 下編譯經過編程
----------------------------------------------------------------------windows
SQLite 的 C 語言編程
執行sql語句
int
sqlite3_exec ( sqlite3 *db, // 使用 sqlite3_open () 打開的數據庫對象。
const char *sql, // 一條待查詢的 SQL 語句
sqlite3_callback, // 自定義的回調函數,對查詢結果每一行都執行一次這個函數
void *,
char **errmsg
);
<example>數組
這是最經常使用的執行 sql 語句的調用。簡單的參數含意標在上面函數中,下面對重
要參數含意詳細註釋:緩存
- 第 4 個參數 "void *" 是調用者所提供的指針,能夠傳遞任何一個指針參數到
這裏,這個參數最終會傳到回調函數裏面,這個指針比較重要,能夠用來做參
數的傳遞。若是不須要傳遞指針給回調函數,能夠填NULL。等下咱們再看回調
函數的寫法,以及這個參數的使用。
- 第 5 個參數 "char ** errmsg" 是錯誤信息。注意是指針的指針。sqlite3裏
面有不少固定的錯誤信息。執行 sqlite3_exec 以後,執行失敗時能夠查閱這
個指針(直接 printf(「%s\n」,errmsg))獲得一串字符串信息,這串信息告訴
你錯在什麼地方。sqlite3_exec函數經過修改你傳入的指針的指針,把你提供
的指針指向錯誤提示信息,這樣sqlite3_exec函數外面就能夠經過這個
char*獲得具體錯誤提示。
說明:一般, sqlite3_callback 和它後面的 void * 這兩個位置均可以填
NULL。填NULL表示你不須要回調。好比你作 insert 操做,作 delete 操做,就
沒有必要使用回調。而當你作 select 時,就要使用回調,由於 sqlite3 把數據
查出來,得經過回調告訴你查出了什麼數據。
** exec 的回調函數
<example>
typedef int
(*sqlite3_callback) (void *, // 這就是上面函數傳遞的 void * 參數,須要強制類型轉換後才能使用。
int, // 查詢結果的列數,即有多少個字段數
char **, // 保存查詢結果
char ** // 各個字段的名字
);
回調函數必須定義成上面這個函數的類型。下面給個簡單的例子:
不使用回調查詢數據庫
上面介紹的 sqlite3_exec 是使用回調來執行 select 操做。還有一個方法能夠直接查詢而不須要回調。雖然回調顯得代碼整齊,但有時候你仍是想要非回調的 select 查詢。這能夠經過 sqlite3_get_table 函數作到。
int
sqlite3_get_table (sqlite3 *, // 打開的數據庫對象指針
const char * sql, // 要查詢的 sql 語句
char *** resultp, // 查詢結果
int * nrow, // 查詢出多少條記錄(即查出多少行)
int * ncolumn, // 多少個字段(多少列)
char ** errmsg // 錯誤信息
);
第3個參數是查詢結果,它依然一維數組(不要覺得是二維數組,更不要覺得是三維數組)。它內存佈局是:第一行是字段名稱,後面是緊接着是每一個字段的值。下面用例子來講事。
下面給個簡單例子:
int main( int , char ** )
{
sqlite3 * db;
int result;
char * errmsg = NULL;
char ** dbResult; //是 char ** 類型,兩個*號
int nRow, nColumn;
int i , j;
int index;
result = sqlite3_open( 「c:\\Dcg_database.db」, &db );
if( result != SQLITE_OK )
{
//數據庫打開失敗
return -1;
}
//數據庫操做代碼
//假設前面已經建立了 MyTable_1 表
//開始查詢,傳入的 dbResult 已是 char **,這裏又加了一個 & 取地址符,傳遞進去的就成了 char ***
result = sqlite3_get_table( db, 「select * from MyTable_1」, &dbResult, &nRow, &nColumn, &errmsg );
if( SQLITE_OK == result )
{
//查詢成功
index = nColumn; //前面說過 dbResult 前面第一行數據是字段名稱,從 nColumn 索引開始纔是真正的數據
printf( 「查到%d條記錄\n」, nRow );
for( i = 0; i < nRow ; i++ )
{
printf( 「第 %d 條記錄\n」, i+1 );
for( j = 0 ; j < nColumn; j++ )
{
printf( 「字段名:%s ß> 字段值:%s\n」, dbResult[j], dbResult [index] );
++index; // dbResult 的字段值是連續的,從第0索引到第 nColumn - 1索引都是字段名稱,從第 nColumn 索引開始,後面都是字段值,它把一個二維的表(傳統的行列表示法)用一個扁平的形式來表示
}
printf( 「-------\n」 );
}
}
//到這裏,不論數據庫查詢是否成功,都釋放 char** 查詢結果,使用 sqlite 提供的功能來釋放
sqlite3_free_table( dbResult );
//關閉數據庫
sqlite3_close( db );
return 0;
}
操做二進制
sqlite 操做二進制數據須要用一個輔助的數據類型:sqlite3_stmt * 。這個數據類型記錄了一個「sql語句」。爲何我把 「sql語句」 用雙引號引發來?由於你能夠把 sqlite3_stmt * 所表示的內容當作是 sql語句,可是實際上它不是咱們所熟知的sql語句。它是一個已經把sql語句解析了的、用sqlite本身標記記錄的內部數據結構。正由於這個結構已經被解析了,因此你能夠往這個語句裏插入二進制數據。固然,把二進制數據插到 sqlite3_stmt 結構裏可不能直接 memcpy ,也不能像 std::string 那樣用 + 號。必須用 sqlite 提供的函數來插入。
寫入二進制
要插入二進制,前提是這個表的字段的類型是 blob 類型。假設有這麼一張表:
create table Tbl_2( ID integer, file_content blob )
首先聲明
sqlite3_stmt * stat;
而後,把一個 sql 語句解析到 stat 結構裏去:
sqlite3_prepare( db, 「insert into Tbl_2( ID, file_content) values( 10, ? )」, -1, &stat, 0 );
上面的函數完成 sql 語句的解析。
第一個參數跟前面同樣,是個 sqlite3 * 類型變量
第二個參數是一個 sql 語句。這個 sql 語句特別之處在於 values 裏面有個 ? 號。在sqlite3_prepare函數裏,?號表示一個未定的值,它的值等下才插入。
第三個參數我寫的是-1,這個參數含義是前面 sql 語句的長度。若是小於 0,sqlite會自動計算它的長度(把sql語句當成以\0結尾的字符串)。
第四個參數是 sqlite3_stmt 的指針的指針。解析之後的sql語句就放在這個結構裏。
第五個參數我也不知道是幹什麼的。爲0就能夠了。
若是這個函數執行成功(返回值是 SQLITE_OK 且 stat 不爲NULL ),那麼下面就能夠開始插入二進制數據。
sqlite3_bind_blob( stat, 1, pdata, (int)(length_of_data_in_bytes), NULL );
// pdata爲數據緩衝區,length_of_data_in_bytes爲數據大小,以字節爲單位
這個函數一共有5個參數。
第 1 個參數:是前面prepare獲得的 sqlite3_stmt * 類型變量。
第 2 個參數:?號的索引。前面prepare的sql語句裏有一個?號,假若有多個?號怎麼插入?方法就是改變 bind_blob 函數第2個參數。這個參數我寫1,表示這裏插入的值要替換 stat 的第一個?號(這裏的索引從1開始計數,而非從0 開始)。若是你有多個?號,就寫多個 bind_blob 語句,並改變它們的第2個參數就替換到不一樣的?號。若是有?號沒有替換,sqlite爲它取值null。
第3個參數:二進制數據起始指針。
第4個參數:二進制數據的長度,以字節爲單位。
第5個參數:是個析夠回調函數,告訴sqlite當把數據處理完後調用此函數來析夠你的數據。這個參數我尚未使用過,所以理解也不深入。可是通常都填 NULL,須要釋放的內存本身用代碼來釋放。
bind完了以後,二進制數據就進入了你的「sql語句」裏了。你如今能夠把它保存到數據庫裏:
int result = sqlite3_step( stat );
經過這個語句,stat 表示的sql語句就被寫到了數據庫裏。最後,要把 sqlite3_stmt 結構給釋放:
sqlite3_finalize( stat ); //把剛纔分配的內容析構掉
讀出二進制
先聲明 sqlite3_stmt * 類型變量:
sqlite3_stmt * stat;
而後,把一個 sql 語句解析到 stat 結構裏去:
sqlite3_prepare( db, 「select * from Tbl_2」, -1, &stat, 0 );
當 prepare 成功以後(返回值是 SQLITE_OK ),開始查詢數據。
int result = sqlite3_step( stat );
這一句的返回值是 SQLITE_ROW 時表示成功(不是 SQLITE_OK )。
你能夠循環執行 sqlite3_step 函數,一次 step 查詢出一條記錄。直到返回值不爲 SQLITE_ROW 時表示查詢結束。
而後開始獲取第一個字段:ID 的值。ID是個整數,用下面這個語句獲取它的值:
int id = sqlite3_column_int( stat, 0 );
//第2個參數表示獲取第幾個字段內容,從0開始計算,由於個人表的ID字段是第一個字段,所以這裏我填0
下面開始獲取 file_content 的值,由於 file_content 是二進制,所以我須要獲得它的指針,還有它的長度:
const void * pFileContent = sqlite3_column_blob( stat, 1 );
int len = sqlite3_column_bytes( stat, 1 );
這樣就獲得了二進制的值。把 pFileContent 的內容保存出來以後,不要忘了釋放 sqlite3_stmt 結構:
sqlite3_finalize( stat ); //把剛纔分配的內容析構掉
重複使用 sqlite3_stmt 結構
若是你須要重複使用 sqlite3_prepare 解析好的 sqlite3_stmt 結構,須要用函數: sqlite3_reset。
result = sqlite3_reset(stat);
這樣, stat 結構又成爲 sqlite3_prepare 完成時的狀態,你能夠從新爲它 bind 內容。
------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"
#include <string.h>
int main(int argc, char **argv)
{
int rc, i, ncols;
sqlite3 *db;
sqlite3_stmt *stmt;
char *sql;
const char *tail;
//打開數據
rc = sqlite3_open("foods.db", &db);
if(rc) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
sql = "select * from episodes";
//預處理
rc = sqlite3_prepare(db, sql, (int)strlen(sql), &stmt, &tail);
if(rc != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
}
rc = sqlite3_step(stmt);
ncols = sqlite3_column_count(stmt);
while(rc == SQLITE_ROW) {
for(i=0; i < ncols; i++) {
fprintf(stderr, "'%s' ", sqlite3_column_text(stmt, i));
}
fprintf(stderr, "\n");
rc = sqlite3_step(stmt);
}
//釋放statement
sqlite3_finalize(stmt);
//關閉數據庫
sqlite3_close(db);
return 0;
}
---------------------------------------------------------------
參看API說明://http://www.sqlite.org/cintro.html
編譯器:VC6.0
數據庫:sqlite
頭文件包:sqlite-amalgamation-3070601
使用時將sqlite3.h,sqlite3.c拷到目錄下,或者直接添加include路徑
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"
//回調函數print的編寫;
//其中data爲sqlite3_exec中的第四個參數
//第二個參數是欄的數目
//第三個是欄的名字
//第四個爲查詢獲得的值得
//這兩個函數輸出全部查詢到的結果
//該函數會被插入到每一行結果中
int print(void *data, int n_columns, char **column_values, char **column_names)
{
int i;
for(i = 0; i < n_columns; ++i)
printf("列名:%s\n列值:%s\n", column_names[i], column_values[i]);
return 0;
}
char *datafile = "test.s3db";
char *createsql = "CREATE TABLE [test] ([id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [name] TEXT NOT NULL, [sex] TEXT NOT NULL);";
char *selectsql = "select * from test";
char *insertsql = "insert into test(name, sex) values(\'hahahah\', \'man\');";
char *deletesql = "delete from test where id < 6;";
int main(void)
{
sqlite3 *db=NULL;
char *errMsg;
int rc;
//打開一個數據庫,若是改數據庫不存在,則建立一個名字爲datafile的數據庫文件
if((rc = sqlite3_open(datafile, &db)) != SQLITE_OK)
{
fprintf(stderr, "打開數據庫失敗: %s\n", sqlite3_errmsg(db));
return 0;
}
else
{
if((rc = sqlite3_exec(db, createsql, 0, 0, &errMsg)) != SQLITE_OK)
{
printf("建立數據庫失敗:%s\n", errMsg);
return 0;
}
else
{
printf("建立表test成功\n");
}
}
if((rc = sqlite3_exec(db, selectsql, print, 0, &errMsg)) != SQLITE_OK)//查詢
{
printf("查詢錯誤:%s\n", errMsg);
}
printf("插入操做=========================================\n");
if((rc = sqlite3_exec(db, insertsql, 0, 0, &errMsg)) != SQLITE_OK)//刪除
{
printf("插入錯誤:%s\n", errMsg);
}
if((rc = sqlite3_exec(db, selectsql, print, 0, &errMsg)) != SQLITE_OK)//查詢
{
printf("查詢錯誤:%s\n", errMsg);
}
printf("刪除操做=========================================\n");
if((rc = sqlite3_exec(db, deletesql, 0, 0, &errMsg)) != SQLITE_OK)//刪除
{
printf("刪除錯誤:%s\n", errMsg);
}
if((rc = sqlite3_exec(db, selectsql, print, 0, &errMsg)) != SQLITE_OK)//查詢
{
printf("查詢錯誤:%s\n", errMsg);
}
printf((sqlite3_close(db) == SQLITE_OK)?"close sqlite success\n":"close sqlite failed\n");//關閉數據庫
return 0;
}
-----------------------------------------------------------------
// name: query.c
// This prog is used to test C/C++ API for sqlite3 .It is very simple,ha !
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"
//#define _DEBUG_
int main( void )
{
sqlite3 *db=NULL;
char *zErrMsg = 0;
char *dbPath = "/usr/tomcat6/webapps/sql/WEB-INF/classes/sq3.s3db";
int rc;
rc = sqlite3_open(dbPath, &db); //打開指定的數據庫文件,若是不存在將建立一個同名的數據庫文件
if( rc )
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
else
{
printf("You have opened a sqlite3 database saved in %s successfully!\n",dbPath);
}
//建立一個表,若是該表存在,則不建立,
//返回值爲SQLITE_OK爲成功
//函數參數:第一個爲操做數據庫的指針,第二句爲SQL命令字符串
//第三個參數爲callback函數,這裏沒有用,第四個參數爲callback函數
//第五個參數給出提示信息,存儲在 zErrMsg 中
char *sql = " CREATE TABLE SensorData(\
ID INTEGER PRIMARY KEY,\
SensorID INTEGER,\
SiteNum INTEGER,\
Time VARCHAR(12),\
SensorParameter REAL\
);" ;
sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );
#ifdef _DEBUG_
printf("zErrMsg = %s \n", zErrMsg);
#endif
//插入數據
sql = "INSERT INTO \"SensorData\" VALUES(NULL , 1 , 1 , '200605011206', 18.9 );" ;
sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );
sql = "INSERT INTO \"SensorData\" VALUES(NULL , 1 , 1 , '200605011306', 16.4 );" ;
sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );
int nrow = 0, ncolumn = 0;
char **azResult; //二維數組存放結果
//查詢數據
/*
int sqlite3_get_table(sqlite3*, const char *sql,char***result , int *nrow , int *ncolumn ,char **errmsg );
result中是以數組的形式存放你所查詢的數據,首先是表名,再是數據。
nrow ,ncolumn分別爲查詢語句返回的結果集的行數,列數,沒有查到結果時返回0
*/
sql = "SELECT * FROM SensorData ";
sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
int i = 0 ;
printf( "row:%d column=%d \n" , nrow , ncolumn );
printf( "\nThe result of querying is : \n" );
for( i=0 ; i<( nrow + 1 ) * ncolumn ; i++ )
printf( "azResult[%d] = %s\n", i , azResult[i] );
//釋放掉 azResult 的內存空間
sqlite3_free_table( azResult );
#ifdef _DEBUG_
printf("zErrMsg = %s \n", zErrMsg);
#endif
sqlite3_close(db); //關閉數據庫
return 0;
}
--------------------------------------------------------
.5 寫個C語言程序調用SQLite
如今咱們來寫個C/C++程序,調用 sqlite 的 API 接口函數。
下面是一個C程序的例子,顯示怎麼使用 sqlite 的 C/C++ 接口. 數據庫的名字由第一個參數取得且第二個參數或更多的參數是 SQL 執行語句. 這個函數調用sqlite3_open() 在 22 行打開數據庫, sqlite3_exec() 在 27 行執行 SQL 命令, 而且sqlite3_close() 在 31 行關閉數據庫鏈接。
代碼:
// name: opendbsqlite.c
// This file is used to test C/C++ API for sqlite
// Author : zieckey
// 2006/04/11
#include
#include
int main( void )
{
sqlite3 *db=NULL;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open("zieckey.db", &db); //打開指定的數據庫文件,若是不存在將建立一個同名的數據庫文件
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
else printf("open zieckey.db successfully!\n");
sqlite3_close(db); //關閉數據庫
return 0;
}
編譯:# gcc opendbsqlite.c -o db.out
也許會碰到相似這樣的問題:
/tmp/ccTkItnN.o(.text+0x2b): In function `main':
: undefined reference to `sqlite3_open'
/tmp/ccTkItnN.o(.text+0x45): In function `main':
: undefined reference to `sqlite3_errmsg'
/tmp/ccTkItnN.o(.text+0x67): In function `main':
: undefined reference to `sqlite3_close'
/tmp/ccTkItnN.o(.text+0x8f): In function `main':
: undefined reference to `sqlite3_close'
collect2: ld returned 1 exit status
這是個沒有找到庫文件的問題。
因爲用到了用戶本身的庫文件,所用應該指明所用到的庫,咱們能夠這樣編譯:
# gcc opendbsqlite.c -o db.out -lsqlite3
我用用 -lsqlite3 選項就能夠了(前面咱們生成的庫文件是 libsqlite3.so.0.8.6 等,
去掉前面的lib和後面的版本標誌,就剩下 sqlite3 了因此是 -lsqlite3 )。
若是咱們在編譯安裝的時候,選擇了安裝路徑,例如這樣的話:
.......
# ../sqlite/configure --prefix=/usr/local/arm-linux/sqlite-ix86-linux
.......
這樣編譯安裝時,sqlite的庫文件將會生成在 /usr/local/arm-linux/sqlite-ix86-linux/lib 目錄下
這時編譯還要指定庫文件路徑,由於系統默認的路徑沒有包含 /usr/local/arm-linux/sqlite-ix86-linux/lib
# gcc opendbsqlite.c -lsqlite3 -L/usr/local/arm-linux/sqlite-ix86-linux/lib
若是還不行的話,可能還須要指定頭文件 sqlite3.h 的路徑,以下:
# gcc opendbsqlite.c -lsqlite3 -L/usr/local/arm-linux/sqlite-ix86-linux/lib -I/usr/local/arm-linux/sqlite-ix86-linux/include
這樣編譯應該就能夠了 ,運行:
# ./db.out
open zieckey.db successfully!
是否是頗有成就感阿 ,呵呵,這個上手仍是很快的。
------------------------------------------------------------------------------------------
1、SQLite簡介
SQLite 支持多數SQL92標準,例如:索引、限制、觸發和查看支持。支持 NULL、INTEGER、REAL、TEXT 和 BLOB 數據類型,支持事務。
sqlite支持的sql92標準有:
begin transaction;end transaction;commit transaction;rollback transaction;select,update,delete,insert
create index,table,trigger,view
drop index,table,trigger,view
SQLite 實現了完備的、可嵌入的、零配置的SQL數據庫引擎。它的特色包括 [2]:
1. 事務處理是原子的、一致的、獨立的和持久的(ACID),即便在系統崩潰和掉電之後。
2. 零配置,即不須要設置和管理。
3. 實現了絕大部分的SQL92標準。
4. 一個單獨的磁盤文件存儲一個完整的數據庫。
5. 數據庫文件在機器之間可自由共享。
6. 支持數據庫文件大小至2TB.
7. 字符串和BLOG的大小隻受限於可用存儲器容量。
8. 代碼量小,即小於30K的C代碼行和小於250K的代碼空間(gcc 在i486上)
9. 對於絕大多數普通操做來講,比流行的C/S 模式的數據庫引擎運行速度快。
10. API 簡單、易用。
2、下載SQLite
SQLite能夠到官方站點下載 http://www.sqlite.org/download.html 包括:Linux,Mac OS X, Windows下的已編譯文件以及源代碼、幫助文檔。
1.下載sqlite庫文件(放到e:\sqlite\sqlite3.exe)
2.在CMD下進入到e:\sqlite下
3.在CMD下輸入sqlite3.exe c:\\test.db; (打開數據庫;c:\\test.db不存在則建立)
4.進入數據庫後就可使用sql的四個命令了;(注意sql命令必須加;號)
5.兩個工具:Sqlite Developer和SQLite Administrator
3、SQLite的簡單使用
3.1 創建數據庫 C:\sqlite-3_6_11> sqlite3.exe dbname.db //sqlite3.exe後面跟數據庫文件名3.2 建立數據表 sqlite> create table users(userid varchar(20) PRIMARY KEY, age int, birthday datetime);3.3 添加記錄 insert into users values('張三',20,'1989-05-04');3.4 查詢記錄 select * from users order by birthday;
3.5 刪除記錄 delete from users where userid='wang';
3.6 退出sqlite sqlite> .exit
SQLite數據庫的數據結構是存貯在 "sqlite_master" 表中 具體命令能夠輸入 .help查看或參考幫助文檔
.database 顯示文件中的數據庫列表(沒有附加數據庫,則只有main數據庫)
.table 羅列出全部的表名稱
.dump 以sql格式輸出表結構和表中的數據
.schem 以sql格式輸出表結構
.separator str 設置分隔符
.import file table 將文件中數據導入到表中;各字段以separator爲分隔符(默認|分割符)
.output file&stdout 設置查詢輸出到文件中或屏幕上
.read file 執行文件中的sql語句
.backup ?db? file 備份數據庫(不附加數據庫, test.db文件中只有main數據庫)
.restore ?db? file 恢復數據庫
.head on|off select查詢的時候顯示隱藏字段名
.indices table 列出表的索引名稱.nullvalue STRING 用STRING代替null值顯示
4、編譯LIB
須要到SQLite網站下載sqlitedll-3_6_11.zip,以VS 2008爲例:
在DOS命令行下:
PATH = D:\Program Files\Microsoft Visual Studio 9.0\VC\bin;%PATH% PATH = D:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE;%PATH% LIB /DEF:sqlite3.def /machine:IX86
5、在VC下使用
#include "../sqlite3_lib/sqlite3.h" // 加入頭文件 #pragma comment(lib, "../sqlite3_lib/sqlite3.lib") // 連接lib庫
#include"../sqlite3_lib/sqlite3.h"// 頭文件
#pragma comment(lib, "../sqlite3_lib/sqlite3.lib") // lib靜態庫
// select_callback是select的回調函數
// @data : 是sqlite3_exec()中的第四個參數
// @col_count : 選擇出來的列的個數
// @col_values: 每條記錄每一列的數值
// @col_Name : 每一列的列名
staticint select_callback(void * data, int col_count, char ** col_values, char ** col_Name)
{
// 每條記錄回調一次該函數,有多少條就回調多少次
int i;
for ( i=0; i < col_count; i++ )
{
printf( "%s = %s\n", col_Name[i], col_values[i] == 0 ? "NUL" : col_values[i] );
}
return 0;
}
int main(int argc, char * argv[])
{
constchar * sSQL1 = "create table users(userid varchar(20) PRIMARY KEY, age int, birthday datetime);";
char * pErrMsg = 0;
// 鏈接數據庫
sqlite3 * db = 0;
int ret = sqlite3_open("./test.db", &db);
if ( ret != SQLITE_OK )
{
fprintf(stderr, "沒法打開數據庫: %s", sqlite3_errmsg(db));
return(1);
}
printf("數據庫鏈接成功!\n");
// 執行建表SQL
sqlite3_exec( db, sSQL1, 0, 0, &pErrMsg );
if ( ret != SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", pErrMsg);
sqlite3_free(pErrMsg);
}
// 執行插入記錄SQL
sqlite3_exec( db, "insert into users values('張三',20,'2001-5-4');", 0, 0, &pErrMsg);
sqlite3_exec( db, "insert into users values('李四',20,'1970-5-4');", 0, 0, &pErrMsg);
// 查詢數據表, 第四個參數能夠傳遞給回調函數
sqlite3_exec( db, "select * from users;", select_callback, NULL, &pErrMsg);
// 關閉數據庫
sqlite3_close(db);
db = 0;
return 0;
}
總結:
正如SQLite的名稱,SQLite有其適合的應用環境,對於高流量或數據龐大的Web站點,仍是應該考慮使用DBMS
打開數據庫:
說明:打開一個數據庫,文件名不必定要存在,若是此文件不存在, sqlite 會自動建立。第一個參數指文件名,第二個參數則是定義的 sqlite3 ** 結構體指針(關鍵數據結構),這個結構底層細節如何,您不用管它。
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
返回值:表示操所是否正確( SQLITE_OK 操做正常)
二、關閉數據庫:
說明:若是用 sqlite3_open 開啓了一個數據庫,結尾時不要忘了用這個函數關閉數據庫。
int sqlite3_close(sqlite3*); // 參數就是剛纔的結構體,也就是數據庫句柄
//注意在此出錯後,能夠用sqlite3_errmsg(db)來得到錯誤代碼
3 、執行 SQL 語句:
說 明:這個函數的功能是執行一條或者多條 SQL語句,SQL 語句之間用 「;」 號隔開。建議在執行一條或者多條 SQL 語句得時候,指定第三個參數回調函數,在 回調函數中能夠得到執行 Sql 得詳細過程,若是全部 Sql 執行完畢則應該返回 0 ,不然,則說明此次執行並無徹底成功。第五個參數:若是執行失敗(沒有返回 0 )則能夠查看第五個闡述得值。來查看詳細錯誤信息。
int sqlite3_exec(
sqlite3*, /* 已經打開的數據庫句柄 */
const char *sql, /* 要執行的 Sql 語句 */
sqlite_callback, /* 回調函數 */
void *, /* 傳遞給回調函數的參數 */
char **errmsg /* 保存錯誤信息,注意用sqlite3_free(errmsg)來釋放資源 */
);
一般sqlite3_callback和後面的void*這兩個位置均可以填 NULL,表示不須要回調。好比您作 insert,update,delete操做,就沒有必要使用回調。而看成select時,就要使用回調,由於 sqlite3把數據查出來,得經過回調告訴你查出了什麼數據。
4 、 exec 的回調
typedef int (*sqlite3_callback)(void* data, int col_count, char** col_value, char** col_name);
說明:你的回調函數必須定義爲上面這個函數的類型。
// select_callback是select的回調函數
// @data : 是sqlite3_exec()中的第四個參數
// @col_count : 選擇出來的列的個數
// @col_values: 每條記錄每一列的數值
// @col_Name : 每一列的列名
static int select_callback(void * data, int col_count, char ** col_values, char ** col_Name)
#include"../sqlite3_lib/sqlite3.h"// 頭文件
#pragma comment(lib, "../sqlite3_lib/sqlite3.lib") // lib靜態庫
// select_callback是select的回調函數
// @data : 是sqlite3_exec()中的第四個參數
// @col_count : 選擇出來的列的個數
// @col_values: 每條記錄每一列的數值
// @col_Name : 每一列的列名
staticint select_callback(void * notused, int argc, char ** values, char ** colName)
{
// 每條記錄回調一次該函數,有多少條就回調多少次
int i;
for ( i=0; i < argc; i++ )
{
printf( "%s = %s\n", colName[i], values[i] == 0 ? "NUL" : values[i] );
}
return 0;
}
int main(int argc, char * argv[])
{
constchar * sSQL1 = "create table users(userid varchar(20) PRIMARY KEY, age int, birthday datetime);";
char * pErrMsg = 0;
// 鏈接數據庫
sqlite3 * db = 0;
int ret = sqlite3_open("./test.db", &db);
if ( ret != SQLITE_OK )
{
fprintf(stderr, "沒法打開數據庫: %s", sqlite3_errmsg(db));
return(1);
}
printf("數據庫鏈接成功!\n");
// 執行建表SQL
sqlite3_exec( db, sSQL1, 0, 0, &pErrMsg );
if ( ret != SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", pErrMsg);
sqlite3_free(pErrMsg);
}
// 執行插入記錄SQL
sqlite3_exec( db, "insert into users values('張三',20,'2001-5-4');", 0, 0, &pErrMsg);
sqlite3_exec( db, "insert into users values('李四',20,'1970-5-4');", 0, 0, &pErrMsg);
// 查詢數據表
sqlite3_exec( db, "select * from users;", select_callback, 0, &pErrMsg);
// 關閉數據庫
sqlite3_close(db);
db = 0;
return 0;
}
5 、取當前插入位置:
long long int sqlite3_last_insert_rowid(sqlite3*);
功能:返回你前一次插入得位置,從1開始,sqlite3*爲你打開數據庫所獲得得句柄。
六、非回調select查詢:
功能:執行一次查詢 Sql 而且返回獲得一個記錄集。
int sqlite3_get_table(
sqlite3*, /* 已經打開的數據庫句柄 */
const char *sql, /* 要執行的 Sql 語句 */
char ***resultp, /* 保存返回記錄集的指針 */
int *nrow, /* 返回記錄數(多少行) */
int *ncolumn, /* 返回字段數(多少列) */
char **errmsg /* 返回錯誤信息 */
)
說明:第三個參數是查詢結果,它是一維數組,內存佈局爲(n行m列結果),那麼數組的0到m-1行是列名,m到2*m-1是記錄集的第一行數據,之後的以此類推;
#include"../sqlite3_lib/sqlite3.h"// 頭文件
#pragma comment(lib, "../sqlite3_lib/sqlite3.lib") // lib靜態庫
int main( int , char ** )
{
sqlite3 * db;
int result;
char * errmsg = NULL;
char **dbResult;
int nRow, nColumn;
int i , j;
int index;
// 打開數據庫
result = sqlite3_open( "./test.db", &db );
if( result != SQLITE_OK )
{
return -1;
}
// 數據庫操做代碼
// 假設前面已經建立了 MyTable_1 表
// 開始查詢,傳入的dbResult已是char**,這裏又加了一個&取地址符,傳遞進去的就成了char***
result = sqlite3_get_table( db, "select * from users;", &dbResult, &nRow, &nColumn, &errmsg );
if( SQLITE_OK == result )
{
// 查詢成功
printf( "查到 %d 條記錄,ncolumn=%d \n", nRow, nColumn);
for( i = 1; i <= nRow ; i++ )
{
printf( "第 %d 條記錄 \n", i );
for( j = 0 ; j < nColumn; j++ )
{
printf( " 字段名 :%s > 字段值 :%s\n", dbResult[j], dbResult[i*nColumn + j] );
// dbResult的字段值是連續的,從第0索引到第nColumn-1索引都是字段名稱,從第nColumn索引開始,
// 後面都是字段值,它把一個二維的表(傳統的行列表示法)用一個扁平的形式來表示
}
printf( "-------\n" );
}
}
// 到這裏,不論數據庫查詢是否成功,都釋放 char** 查詢結果,使用 sqlite 提供的功能來釋放
sqlite3_free_table( dbResult );
// 關閉數據庫
sqlite3_close( db );
return 0;
}
7 、釋放查詢結果:
功能:釋放當前查詢的記錄集所佔用的內存
void sqlite3_free_table(char **result);
1.0 總覽
SQLite3是SQLite一個全新的版本,它雖然是在SQLite 2.8.13的代碼基礎之上開發的,可是使用了和以前的版本不兼容的數據庫格式和API. SQLite3是爲了知足如下的需求而開發的:
支持UTF-16編碼.
用戶自定義的文本排序方法.
能夠對BLOBs字段創建索引.
所以爲了支持這些特性我改變了數據庫的格式,創建了一個與以前版本不兼容的3.0版. 至於其餘的兼容性的改變,例如全新的API等等,都將在理論介紹以後向你說明,這樣可使你最快的一次性擺脫兼容性問題.
3.0版的和2.X版的API很是類似,可是有一些重要的改變須要注意. 全部API接口函數和數據結構的前綴都由"sqlite_"改成了"sqlite3_". 這是爲了不同時使用SQLite 2.X和SQLite 3.0這兩個版本的時候發生連接衝突.
因爲對於C語言應該用什麼數據類型來存放UTF-16編碼的字符串並無一致的規範. 所以SQLite使用了普通的void* 類型來指向UTF-16編碼的字符串. 客戶端使用過程當中能夠把void*映射成適合他們的系統的任何數據類型.
2.0 C/C++ 接口
SQLite 3.0一共有83個API函數,此外還有一些數據結構和預約義(#defines). (完整的API介紹請參看另外一份文檔.) 不過大家能夠放心,這些接口使用起來不會像它的數量所暗示的那麼複雜. 最簡單的程序仍然使用三個函數就能夠完成: sqlite3_open(), sqlite3_exec(), 和 sqlite3_close(). 要是想更好的控制數據庫引擎的執行,可使用提供的sqlite3_prepare()函數把SQL語句編譯成字節碼,而後在使用sqlite3_step()函數來執行編譯後的字節碼. 以sqlite3_column_開頭的一組API函數用來獲取查詢結果集中的信息. 許多接口函數都是成對出現的,同時有UTF-8和UTF-16兩個版本. 而且提供了一組函數用來執行用戶自定義的SQL函數和文本排序函數.
2.1 如何打開關閉數據庫
typedef struct sqlite3 sqlite3;
int sqlite3_open(const char*, sqlite3**);
int sqlite3_open16(const void*, sqlite3**);
int sqlite3_close(sqlite3*);
const char *sqlite3_errmsg(sqlite3*);
const void *sqlite3_errmsg16(sqlite3*);
int sqlite3_errcode(sqlite3*);
sqlite3_open() 函數返回一個整數錯誤代碼,而不是像第二版中同樣返回一個指向sqlite3結構體的指針. sqlite3_open() 和 sqlite3_open16() 的不一樣之處在於sqlite3_open16() 使用UTF-16編碼(使用本地主機字節順序)傳遞數據庫文件名. 若是要建立新數據庫, sqlite3_open16() 將內部文本轉換爲UTF-16編碼, 反之sqlite3_open() 將文本轉換爲UTF-8編碼.
打開或者建立數據庫的命令會被緩存,直到這個數據庫真正被調用的時候纔會被執行. 並且容許使用PRAGMA聲明來設置如本地文本編碼或默認內存頁面大小等選項和參數.
sqlite3_errcode() 一般用來獲取最近調用的API接口返回的錯誤代碼. sqlite3_errmsg() 則用來獲得這些錯誤代碼所對應的文字說明. 這些錯誤信息將以 UTF-8 的編碼返回,而且在下一次調用任何SQLite API函數的時候被清除. sqlite3_errmsg16() 和 sqlite3_errmsg() 大致上相同,除了返回的錯誤信息將以 UTF-16 本機字節順序編碼.
SQLite3的錯誤代碼相比SQLite2沒有任何的改變,它們分別是:
#define SQLITE_OK 0 /* Successful result */
#define SQLITE_ERROR 1 /* SQL error or missing database */
#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* The database file is locked */
#define SQLITE_LOCKED 6 /* A table in the database is locked */
#define SQLITE_NOMEM 7 /* A malloc() failed */
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */
#define SQLITE_MISMATCH 20 /* Data type mismatch */
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
#define SQLITE_ROW 100 /* sqlite_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite_step() has finished executing */
2.2 執行 SQL 語句
typedef int (*sqlite_callback)(void*,int,char**, char**);
int sqlite3_exec(sqlite3*, const char *sql, sqlite_callback, void*, char**);
sqlite3_exec 函數依然像它在SQLite2中同樣承擔着不少的工做. 該函數的第二個參數中能夠編譯和執行零個或多個SQL語句. 查詢的結果返回給回調函數. 更多地信息能夠查看API 參考.
在SQLite3裏,sqlite3_exec通常是被準備SQL語句接口封裝起來使用的.
typedef struct sqlite3_stmt sqlite3_stmt;
int sqlite3_prepare(sqlite3*, const char*, int, sqlite3_stmt**, const char**);
int sqlite3_prepare16(sqlite3*, const void*, int, sqlite3_stmt**, const void**);
int sqlite3_finalize(sqlite3_stmt*);
int sqlite3_reset(sqlite3_stmt*);
sqlite3_prepare 接口把一條SQL語句編譯成字節碼留給後面的執行函數. 使用該接口訪問數據庫是當前比較好的的一種方法.
sqlite3_prepare() 處理的SQL語句應該是UTF-8編碼的. 而sqlite3_prepare16() 則要求是UTF-16編碼的. 輸入的參數中只有第一個SQL語句會被編譯. 第四個參數則用來指向輸入參數中下一個須要編譯的SQL語句存放的SQLite statement對象的指針, 任什麼時候候若是調用 sqlite3_finalize() 將銷燬一個準備好的SQL聲明. 在數據庫關閉以前,全部準備好的聲明都必須被釋放銷燬. sqlite3_reset() 函數用來重置一個SQL聲明的狀態,使得它能夠被再次執行.
SQL聲明能夠包含一些型如"?" 或 "?nnn" 或 ":aaa"的標記, 其中"nnn" 是一個整數,"aaa" 是一個字符串. 這些標記表明一些不肯定的字符值(或者說是通配符),能夠在後面用sqlite3_bind 接口來填充這些值. 每個通配符都被分配了一個編號(由它在SQL聲明中的位置決定,從1開始),此外也能夠用 "nnn" 來表示 "?nnn" 這種狀況. 容許相同的通配符在同一個SQL聲明中出現屢次, 在這種狀況下全部相同的通配符都會被替換成相同的值. 沒有被綁定的通配符將自動取NULL值.
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, long long int);
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 n, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
以上是 sqlite3_bind 所包含的所有接口,它們是用來給SQL聲明中的通配符賦值的. 沒有綁定的通配符則被認爲是空值. 綁定上的值不會被sqlite3_reset()函數重置. 可是在調用了sqlite3_reset()以後全部的通配符均可以被從新賦值.
在SQL聲明準備好以後(其中綁定的步驟是可選的), 須要調用如下的方法來執行:
int sqlite3_step(sqlite3_stmt*);
若是SQL返回了一個單行結果集,sqlite3_step() 函數將返回 SQLITE_ROW , 若是SQL語句執行成功或者正常將返回 SQLITE_DONE , 不然將返回錯誤代碼. 若是不能打開數據庫文件則會返回 SQLITE_BUSY . 若是函數的返回值是 SQLITE_ROW, 那麼下邊的這些方法能夠用來得到記錄集行中的數據:
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
int sqlite3_column_count(sqlite3_stmt*);
const char *sqlite3_column_decltype(sqlite3_stmt *, int iCol);
const void *sqlite3_column_decltype16(sqlite3_stmt *, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
long long int sqlite3_column_int64(sqlite3_stmt*, int iCol);
const char *sqlite3_column_name(sqlite3_stmt*, int iCol);
const void *sqlite3_column_name16(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
sqlite3_column_count()函數返回結果集中包含的列數. sqlite3_column_count() 能夠在執行了 sqlite3_prepare()以後的任什麼時候刻調用. sqlite3_data_count()除了必須要在sqlite3_step()以後調用以外,其餘跟sqlite3_column_count() 大同小異. 若是調用sqlite3_step() 返回值是 SQLITE_DONE 或者一個錯誤代碼, 則此時調用sqlite3_data_count() 將返回 0 ,然而 sqlite3_column_count() 仍然會返回結果集中包含的列數.
返回的記錄集經過使用其它的幾個 sqlite3_column_***() 函數來提取, 全部的這些函數都把列的編號做爲第二個參數. 列編號從左到右以零起始. 請注意它和以前那些從1起始的參數的不一樣.
sqlite3_column_type()函數返回第N列的值的數據類型. 具體的返回值以下:
#define SQLITE_INTEGER 1
#define SQLITE_FLOAT 2
#define SQLITE_TEXT 3
#define SQLITE_BLOB 4
#define SQLITE_NULL 5
sqlite3_column_decltype() 則用來返回該列在 CREATE TABLE 語句中聲明的類型. 它能夠用在當返回類型是空字符串的時候. sqlite3_column_name() 返回第N列的字段名. sqlite3_column_bytes() 用來返回 UTF-8 編碼的BLOBs列的字節數或者TEXT字符串的字節數. sqlite3_column_bytes16() 對於BLOBs列返回一樣的結果,可是對於TEXT字符串則按 UTF-16 的編碼來計算字節數. sqlite3_column_blob() 返回 BLOB 數據. sqlite3_column_text() 返回 UTF-8 編碼的 TEXT 數據. sqlite3_column_text16() 返回 UTF-16 編碼的 TEXT 數據. sqlite3_column_int() 以本地主機的整數格式返回一個整數值. sqlite3_column_int64() 返回一個64位的整數. 最後, sqlite3_column_double() 返回浮點數.
不必定非要按照sqlite3_column_type()接口返回的數據類型來獲取數據. 數據類型不一樣時軟件將自動轉換.
2.3 用戶自定義函數
可使用如下的方法來建立用戶自定義的SQL函數:
typedef struct sqlite3_value sqlite3_value;
int sqlite3_create_function(
sqlite3 *,
const char *zFunctionName,
int nArg,
int eTextRep,
void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
int sqlite3_create_function16(
sqlite3*,
const void *zFunctionName,
int nArg,
int eTextRep,
void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
#define SQLITE_UTF8 1
#define SQLITE_UTF16 2
#define SQLITE_UTF16BE 3
#define SQLITE_UTF16LE 4
#define SQLITE_ANY 5
nArg 參數用來代表自定義函數的參數個數. 若是參數值爲0,則表示接受任意個數的參數. 用 eTextRep 參數來代表傳入參數的編碼形式. 參數值能夠是上面的五種預約義值. SQLite3 容許同一個自定義函數有多種不一樣的編碼參數的版本. 數據庫引擎會自動選擇轉換參數編碼個數最少的版本使用.
普通的函數只須要設置 xFunc 參數,而把 xStep 和 xFinal 設爲NULL. 聚合函數則須要設置 xStep 和 xFinal 參數,而後把 xFunc 設爲NULL. 該方法和使用sqlite3_create_aggregate() API同樣.
sqlite3_create_function16()和sqlite_create_function()的不一樣就在於自定義的函數名一個要求是 UTF-16 編碼,而另外一個則要求是 UTF-8.
請注意自定函數的參數目前使用了sqlite3_value結構體指針替代了SQLite version 2.X中的字符串指針. 下面的函數用來從sqlite3_value結構體中提取數據:
const void *sqlite3_value_blob(sqlite3_value*);
int sqlite3_value_bytes(sqlite3_value*);
int sqlite3_value_bytes16(sqlite3_value*);
double sqlite3_value_double(sqlite3_value*);
int sqlite3_value_int(sqlite3_value*);
long long int sqlite3_value_int64(sqlite3_value*);
const unsigned char *sqlite3_value_text(sqlite3_value*);
const void *sqlite3_value_text16(sqlite3_value*);
int sqlite3_value_type(sqlite3_value*);
上面的函數調用如下的API來得到上下文內容和返回結果:
void *sqlite3_aggregate_context(sqlite3_context*, int nbyte);
void *sqlite3_user_data(sqlite3_context*);
void sqlite3_result_blob(sqlite3_context*, const void*, int n, void(*)(void*));
void sqlite3_result_double(sqlite3_context*, double);
void sqlite3_result_error(sqlite3_context*, const char*, int);
void sqlite3_result_error16(sqlite3_context*, const void*, int);
void sqlite3_result_int(sqlite3_context*, int);
void sqlite3_result_int64(sqlite3_context*, long long int);
void sqlite3_result_null(sqlite3_context*);
void sqlite3_result_text(sqlite3_context*, const char*, int n, void(*)(void*));
void sqlite3_result_text16(sqlite3_context*, const void*, int n, void(*)(void*));
void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
void *sqlite3_get_auxdata(sqlite3_context*, int);
void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
2.4 用戶自定義排序規則
下面的函數用來實現用戶自定義的排序規則:
sqlite3_create_collation(sqlite3*, const char *zName, int eTextRep, void*,
int(*xCompare)(void*,int,const void*,int,const void*));
sqlite3_create_collation16(sqlite3*, const void *zName, int eTextRep, void*,
int(*xCompare)(void*,int,const void*,int,const void*));
sqlite3_collation_needed(sqlite3*, void*,
void(*)(void*,sqlite3*,int eTextRep,const char*));
sqlite3_collation_needed16(sqlite3*, void*,
void(*)(void*,sqlite3*,int eTextRep,const void*));
sqlite3_create_collation() 函數用來聲明一個排序序列和實現它的比較函數. 比較函數只能用來作文本的比較. eTextRep 參數能夠取以下的預約義值 SQLITE_UTF8, SQLITE_UTF16LE, SQLITE_UTF16BE, SQLITE_ANY,用來表示比較函數所處理的文本的編碼方式. 同一個自定義的排序規則的同一個比較函數能夠有 UTF-8, UTF-16LE 和 UTF-16BE 等多個編碼的版本. sqlite3_create_collation16()和sqlite3_create_collation() 的區別也僅僅在於排序名稱的編碼是 UTF-16 仍是 UTF-8.
可使用 sqlite3_collation_needed() 函數來註冊一個回調函數,當數據庫引擎遇到未知的排序規則時會自動調用該函數. 在回調函數中能夠查找一個類似的比較函數,並激活相應的sqlite_3_create_collation()函數. 回調函數的第四個參數是排序規則的名稱,一樣sqlite3_collation_needed採用 UTF-8 編碼. sqlite3_collation_need16() 採用 UTF-16 編碼.
-----------------------------------------------------
SQLite 不支持的 SQL 特性
相對於試圖列出 SQLite 支持的全部 SQL92 特性,只列出不支持的部分要簡單得多。下面顯示的就是 SQLite 所不支持的 SQL92 特性。
這個列表的順序關係到什麼時候一個特性可能被加入到SQLite。接近列表頂部的特性更可能在不遠的未來加入。接近列表底部的特性尚且沒有直接的計劃。
外鍵約束(FOREIGN KEY constraints)
外鍵約束會被解析但不會被執行。
完整的觸發器支持(Complete trigger support)
如今有一些觸發器的支持,可是還不完整。 缺乏的特性包括 FOR EACH STATEMENT 觸發器(如今全部的觸發器都必須是 FOR EACH ROW ), 在表上的 INSTEAD OF 觸發器(如今 INSTEAD OF 觸發器只容許在視圖上), 以及遞歸觸發器——觸發自身的觸發器。
完整的 ALTER TABLE 支持(Complete ALTER TABLE support)
只支持 ALTER TABLE 命令的 RENAME TABLE 和 ADD COLUMN。 其餘類型的 ALTER TABLE 操做如 DROP COLUMN,ALTER COLUMN,ADD CONSTRAINT 等等均被忽略。
嵌套事務(Nested transactions)
如今的實現只容許單一活動事務。
RIGHT 和 FULL OUTER JOIN(RIGHT and FULL OUTER JOIN)
LEFT OUTER JOIN 已經實現,但尚未 RIGHT OUTER JOIN 和 FULL OUTER JOIN。
可寫視圖(Writing to VIEWs)
SQLite 中的視圖是隻讀的。沒法在一個視圖上執行 DELETE,INSERT,UPDATE。 不過你能夠建立一個試圖在視圖上 DELETE,INSERT,UPDATE 時觸發的觸發器,而後在觸發器中完成你所須要的工做。
GRANT 和 REVOKE(GRANT and REVOKE)
因爲 SQLite 讀和寫的是一個普通的磁盤文件, 所以惟一能夠獲取的權限就是操做系統的標準的文件訪問權限。 通常在客戶機/服務器架構的關係型數據庫系統上能找到的 GRANT 和 REVOKE 命令對於一個嵌入式的數據庫引擎來講是沒有意義的, 所以也就沒有去實現。
-------------------------------
---------------------------------------------------------------------------------
SQLite第三版中的數據類型
1.存儲類別
第二版把全部列的值都存儲成ASCII文本格式。第三版則能夠把數據存儲成整數和實數,還能夠存儲BLOB數據.
Each value stored in an SQLite數據庫中存儲的每一個值都有一個屬性,都屬於下面所列類中的一種,(被數據庫引擎所控制)
空.這個值爲空值
整數.值被標識爲整數,依據值的大小能夠依次被存儲爲1,2,3,4,5,6,7,8.
實數. 全部值都是浮動的數值,被存儲爲8字節的IEEE浮動標記序號.
文本. 值爲文本字符串,使用數據庫編碼存儲(TUTF-8, UTF-16BE or UTF-16-LE).
BLOB. 值是BLOB數據,如何輸入就如何存儲,不改變格式.
像SQLite2.0版同樣,在3.0版中,除了INTEGER PRIMARY KEY,數據庫中的任何列均可以存儲任何類型的數據.這一規則也有例外,在下面的"嚴格類似模式"中將描述.
輸入SQLite的全部值,無論它是嵌入 SQL語句中的文字仍是提早編譯好的綁定在SQL語句中的值,在SQL語句執行前都被存儲爲一個類.在下面所描述的狀況下,數據庫引擎將在執行時檢查並把值在數字存儲類(整數和實數)和文本類間轉換.
存儲的類別最初被分類爲以下:
具體的值好比SQL語句部分的帶雙引號或單引號的文字被定義爲文本,若是文字沒帶引號並無小數點或指數則被定義爲整數,若是文字沒帶引號但有小數點或指數則被定義爲實數,若是值是空則被定義爲空值.BLOB數據使用符號X'ABCD'來標識.
Values supplied using the 被輸入的值使用sqlite3_bind_* APIs的被分類一個存儲等級,這等級是和原來的類基本相一致的. (好比sqlite3_bind_blob()綁定一個BLOB的值).
值的分類是SQL分等級操做的結果,決定於最遠的操做表達式.用戶定義的功能也許會把值返回任意的類.在編譯的時候來肯定表達式的存儲類基本是不可能的.
2. 列之間的親和性
在SQLite3.0版中,值被定義爲何類型只和值自身有關,和列沒有關係,和變量也沒有關係. (這有時被稱做
弱類型.)全部其它的咱們所使用的數據庫引擎都受靜態類型系統的限制,其中的全部值的類是由其所屬列的屬性決定的,而和值無關.
爲了最大限度的增長SQLite數據庫和其餘數據庫的兼容性,SQLite支持列的"類型親和性". 列的親和性是爲該列所存儲的數據建議一個類型.咱們要注意是建議而不是強迫.在理論上來說,任何列依然是能夠存儲任何類型的數據的. 只是針對某些列,若是給建議類型的話,數據庫將按所建議的類型存儲.這個被優先使用的數據類型則被稱爲"親和類型".
在SQLite3.0版中,數據庫中的每一列都被定義爲如下親和類型中的一種:
文本
數字的
整數
無
一個具備類型親和性的列按照無類型,文本,或BLOB存儲全部的數據.若是數字數據被插入一個具備文本類型親和性的列,在存儲以前數字將被轉換成文本.
一個具備數字類型親和性的列也許使用全部的五個存儲類型存儲值.當文本數據被插入一個數字列時,在存儲以前,數據庫將嘗試着把文本轉換成整數或實數.若是能成功轉換的話,值將按證書活實數的類型被存儲. 若是不能 成功轉換的話,值則只能按文本類型存儲了,而不會被轉換成無類型或BLOB類型來存儲.
一個具備整數親和力的列在轉換方面和具備數字親和力的列是同樣的,但也有些區別 ,好比沒有浮動量的實值(文本值轉換的值)被插入具備整數親和力的列時,它將被轉換成整數並按整數類型存儲.
一個具備無類型親和力的列不會優先選擇使用哪一個類型.在數據被輸入前它不會強迫數據轉換類型.
2.1 列的親和性的決定
一個列的親和類型是由該列所宣稱的類型決定的.遵照如下規則:
若是數據類型包括字符串"INT"那麼它被定義成具備整數親和性.
若是列中的數據類型包括如下任何的字符串 "CHAR", "CLOB", or "TEXT" 那麼這個列則具備文本親和性.要注意VARCHAR類型包括字符串"CHAR"所以也具備文本類型親和性.
若是一個列的數據類型包括字符串"BLOB"或者若是數據類型被具體化了,那麼這個列具備無類型親和性.
不然就具備數字類型親和性.
若是表格使用If "CREATE TABLE AS SELECT..."語句生成的,那麼全部的列則都沒有具體的數據類型,則沒有類型親和性.
2.2 列的親和性的例子
CREATE TABLE t1(
t TEXT,
nu NUMERIC,
i INTEGER,
no BLOB
);
-- Storage classes for the following row:
-- TEXT, REAL, INTEGER, TEXT
INSERT INTO t1 VALUES('500.0', '500.0', '500.0', '500.0');
-- Storage classes for the following row:
-- TEXT, REAL, INTEGER, REAL
INSERT INTO t1 VALUES(500.0, 500.0, 500.0, 500.0);
3.比較表達式
像SQLite2.0版同樣,3.0版的一個特性是二進制比較符'=', '<', '<=', '>=' and '!=',一個操做'IN'能夠測試固定的成員資格, 三重的比較操做符'BETWEEN'.
比較的結果決定於被比較的兩個值的存儲類型。遵循如下規則:
一個具備空存儲類型的值被認爲小於任何值(包括另一個具備空存儲類型的值)。
一個整數值或實數值小於任何文本值和BLOB值。 當一個整數或實數和另外一個整數或實數相比較的時候,則按照實際數值來比較。
一個文本值小於BLOB值。當兩個文本值相比較的時候,則用C語言類庫中的memcmp()函數來比較。然而,有時候也不是這樣的,好比在下面所描述的「用戶定義的整理順序」狀況下。
當兩個BLOB文本被比較的時候,結果決定於memcmp()函數。
在開始比較前,SQLite嘗試着把值在數字存儲級(整數和實數)和文本之間相互轉換。下面列舉了關於如何比較二進制值的例子。在着重號below中使用的表達式能夠表示SQL標量表達式或是文本但不是一個列值。
當一個列值被比擬爲表達式結果的時候,在比較開始前,列的親和性將被應用在表達結果中。
當兩個列值比較的時候,若是一個列有整數或數字親和性的時候,而另一列卻沒有,那麼數字親和性適用於從非數字列提取的任何具備文本存儲類型的值. P>
當比較兩個表達式的結果時,不發生任何轉換,直接比較結果.若是一個字符串和一個數字比較, 數字老是小於字符串.
在SQLite中, 表達式"a BETWEEN b AND c"等於表達式 "a >= b AND a <= c",在比較表達式時,a能夠是具備任何親和性.
表達式 "a IN (SELECT b ....)" 在比較時遵循上面所提到的三條規則,是二進制比較.(例如, 在一個類似的樣式 "a = b"). 例如,若是'b'是一個列值, 'a' 是一個表達式,那麼,在開始比較前,'b'的親和性就被轉換爲'a'的親和性了.
SQLite把表達式 "a IN (x, y, z)" 和 "a = z OR a = y OR a = z"視爲相等.
3.1 比較例子
CREATE TABLE t1(
a TEXT,
b NUMERIC,
c BLOB
);
-- Storage classes for the following row:
-- TEXT, REAL, TEXT
INSERT INTO t1 VALUES('500', '500', '500');
-- 60 and 40 are converted to '60' and '40' and values are compared as TEXT.
SELECT a < 60, a < 40 FROM t1;
1|0
-- Comparisons are numeric. No conversions are required.
SELECT b < 60, b < 600 FROM t1;
0|1
-- Both 60 and 600 (storage class NUMERIC) are less than '500'
-- (storage class TEXT).
SELECT c < 60, c < 600 FROM t1;
0|0
4. 運算符
全部的數學運算符(全部的運算符而不是連鎖做用標記符"||")運算對象首先具備數字親和性, 若是一個或是兩個都不能被轉換爲數字那麼操做的結果將是空值。
對於鏈接做用操做符,全部操做符將首先具備文本親和性。若是其中任何一個操做符不能被轉換爲文本(由於它是空值或是BLOB)鏈接做用操做符將是空值。
5. 分類,排序,混合挑選
當用子句ORDER挑選值時,空值首先被挑選出來, 而後是整數和實數按順序被挑選出來, 而後是文本值按memcmp()順序被挑選出來, 最後是BLOB值按memcmp()順序被挑選出來.在挑選以前, 沒有存儲類型的值都被轉換了.
When grouping values with the 當用GROUP BY子句給值分組時,具備不一樣存儲類型的值被認爲是不一樣的, 但也有例外, 好比,一個整數值和一個實數值從數字角度來講是相等的,那麼它們則是相等的.用GROUP by 子句比較完後,值不具備任何親和性.
混合挑選操做符UNION, INTERSECT and EXCEPT 在值之間實行絕對的比較,一樣的親和性將被應用於全部的值,這些值將被存儲在一個單獨的具備混合SELECT的結果組的列中. 被賦予的親和性是該列的親和性,這個親和性是由剩下的大部分的混合SELECTS返回的,這些混合SELECTS在那個位置上有列值(而不是其它類型的表達式). 若是一個給定的混合SELECT列沒有SELECTS的量, 那麼在比較前,該列的值將不具備任何親和性.
6. 其它親和性模式
以上的部分所描述的都是數據庫引擎在正常親和性模式下所進行的操做, SQLite將描述其它兩種親和性模式,以下:
嚴格親和性模式.在這種模式下,若是須要值之間相互轉換數據存儲類型的話,數據庫引擎將發送錯誤報告,當前語句也將會從新運行.
無親和性模式.在這種模式下,值的數據存儲類型不發生轉換.具備不一樣存儲類型的值之間不能比較,但整數和實數之間能夠比較.
7.用戶定義的校對順序
By default, when 當SQLite比較兩個文本值的時候,經過系統設定,無論字符串的編碼是什麼,用memcmp()來比較. SQLite第三版容許用戶提供任意的函數來代替memcmp(),也就是用戶定義的比較順序.
除了系統預設的BINARY比較順序,它是用memcmp()函數比較,SQLite還包含了兩個額外的內置比較順序函數, NOCASE和REVERSE:
BINARY -使用memcmp()比較字符串數據, 不考慮文本編碼.
REVERSE -用倒序比較二進制文本.
NOCASE - 和二進制同樣,但在比較以前,26位的大寫字母盤要被摺合成相應的小寫字母盤.
7.1 分配比較順序
每一個表格中的每一個列都有一個預設的比較類型.若是一個比較類型不是二進制所要求的,比較的子句將被具體化爲 列的定義 來定義該列.
當用SQLite比較兩個文本值時,比較順序將按照如下的規則來決定比較的結果.文檔的第三部分和第五部分描述在何種場合下發生這種比較.
對於二進制比較符(=, <, >, <= and >=),若是每一個操做數是一列的話,那麼該列的默認比較類型決定於所使用的比較順序. 若是兩個操做數都是列的話,那麼左邊的操做數的比較類型決定了所要使用的比較順序.若是兩個操做數都不是一列,將使用二進制來比較.
表達式"x BETWEEN y and z"和 "x >= y AND x <= z"是相同的. 表達式"x IN (SELECT y ...)" 和表達式 "x = y" 使用一樣的方法來操做,這是爲了決定所要使用的比較順序.若是X是一列或者二進制的,則"x IN (y, z ...)" 形式的表達式所使用的比較順序是X的默認的比較類型.
ORDER BY clause that is part of a SELECT statement may be assigned a collation sequence to be used for the sort operation explicitly. In this case the explicit collation sequence is always used. Otherwise, if the expression sorted by an ORDER BY clause is a column, then the default collation type of the column is used to determine sort order. If the expression is not a column, then the BINARY collation sequence is used.
7.2 比較順序的例子
下面的例子介紹了The examples below identify the collation sequences that would be used to determine the results of text comparisons that may be performed by various SQL statements. Note that a text comparison may not be required, and no collation sequence used, in the case of numeric, blob or NULL values.
CREATE TABLE t1(
a, -- default collation type BINARY
b COLLATE BINARY, -- default collation type BINARY
c COLLATE REVERSE, -- default collation type REVERSE
d COLLATE NOCASE -- default collation type NOCASE
);
-- Text comparison is performed using the BINARY collation sequence.
SELECT (a = b) FROM t1;
-- Text comparison is performed using the NOCASE collation sequence.
SELECT (d = a) FROM t1;
-- Text comparison is performed using the BINARY collation sequence.
SELECT (a = d) FROM t1;
-- Text comparison is performed using the REVERSE collation sequence.
SELECT ('abc' = c) FROM t1;
-- Text comparison is performed using the REVERSE collation sequence.
SELECT (c = 'abc') FROM t1;
-- Grouping is performed using the NOCASE collation sequence (i.e. values
-- 'abc' and 'ABC' are placed in the same group).
SELECT count(*) GROUP BY d FROM t1;
-- Grouping is performed using the BINARY collation sequence.
SELECT count(*) GROUP BY (d || '') FROM t1;
-- Sorting is performed using the REVERSE collation sequence.
SELECT * FROM t1 ORDER BY c;
-- Sorting is performed using the BINARY collation sequence.
SELECT * FROM t1 ORDER BY (c || '');
-- Sorting is performed using the NOCASE collation sequence.
SELECT * FROM t1 ORDER BY c COLLATE NOCASE;
----------------------------------------------------------------
Sqlite3 的確很好用。小巧、速度快。可是由於非微軟的產品,幫助文檔總以爲不夠。這些天再次研究它,又有一些收穫,這裏把我對 sqlite3 的研究列出來,以備忘記。這裏要註明,我是一個跨平臺專一者,並不喜歡只用 windows 平臺。我之前的工做就是爲 unix 平臺寫代碼。下面我所寫的東西,雖然沒有驗證,可是我已儘可能不使用任何 windows 的東西,只使用標準 C 或標準C++。可是,我沒有嘗試過在別的系統、別的編譯器下編譯,所以下面的敘述若是不正確,則留待之後修改。下面個人代碼仍然用 VC 編寫,由於我以爲VC是一個很不錯的IDE,能夠加快代碼編寫速度(例如配合 Vassist )。下面我所說的編譯環境,是VC2003。若是讀者以爲本身習慣於 unix 下用 vi 編寫代碼速度較快,能夠不用管個人說明,只須要符合本身習慣便可,由於我用的是標準 C 或 C++ 。不會給任何人帶來不便。1、 版本從http://www.sqlite.org/網站可下載到最新的 sqlite 代碼和編譯版本。我寫此文章時,最新代碼是 3.3.17 版本。好久沒有去下載 sqlite 新代碼,所以也不知道 sqlite 變化這麼大。之前不少文件,如今所有合併成一個 sqlite3.c 文件。若是單獨用此文件,是挺好的,省去拷貝一堆文件還擔憂有沒有遺漏。可是也帶來一個問題:此文件太大,快接近7萬行代碼,VC開它整個機器都慢下來了。若是不須要改它代碼,也就不須要打開 sqlite3.c 文件,機器不會慢。可是,下面我要寫經過修改 sqlite 代碼完成加密功能,那時候就比較痛苦了。若是我的水平較高,建議用些簡單的編輯器來編輯,例如 UltraEdit 或 Notepad 。速度會快不少。2、 基本編譯這個不想多說了,在 VC 裏新建 dos 控制檯空白工程,把 sqlite3.c 和 sqlite3.h 添加到工程,再新建一個 main.cpp 文件。在裏面寫:extern "C"
{
#include "./sqlite3.h"
};int main( int , char** )
{
return 0;
}爲何要 extern 「C」 ?若是問這個問題,我不想說太多,這是C++的基礎。要在 C++ 裏使用一段 C 的代碼,必需要用 extern 「C」 括起來。C++跟 C雖然語法上有重疊,可是它們是兩個不一樣的東西,內存裏的佈局是徹底不一樣的,在C++編譯器裏不用extern 「C」括起C代碼,會致使編譯器不知道該如何爲 C 代碼描述內存佈局。可能在 sqlite3.c 里人家已經把整段代碼都 extern 「C」 括起來了,可是你遇到一個 .c 文件就自覺的再括一次,也沒什麼很差。
基本工程就這樣創建起來了。編譯,能夠經過。可是有一堆的 warning。能夠無論它。3、 SQLITE操做入門sqlite提供的是一些C函數接口,你能夠用這些函數操做數據庫。經過使用這些接口,傳遞一些標準 sql 語句(以 char * 類型)給 sqlite 函數,sqlite 就會爲你操做數據庫。sqlite 跟MS的access同樣是文件型數據庫,就是說,一個數據庫就是一個文件,此數據庫裏能夠創建不少的表,能夠創建索引、觸發器等等,可是,它實際上獲得的就是一個文件。備份這個文件就備份了整個數據庫。sqlite 不須要任何數據庫引擎,這意味着若是你須要 sqlite 來保存一些用戶數據,甚至都不須要安裝數據庫(若是你作個小軟件還要求人家必須裝了sqlserver 才能運行,那也太黑心了)。下面開始介紹數據庫基本操做。
(1) 基本流程i.1 關鍵數據結構sqlite 裏最經常使用到的是 sqlite3 * 類型。從數據庫打開開始,sqlite就要爲這個類型準備好內存,直到數據庫關閉,整個過程都須要用到這個類型。當數據庫打開時開始,這個類型的變量就表明了你要操做的數據庫。下面再詳細介紹。i.2 打開數據庫int sqlite3_open( 文件名, sqlite3 ** );用這個函數開始數據庫操做。須要傳入兩個參數,一是數據庫文件名,好比:c:\\DongChunGuang_Database.db。文件名不須要必定存在,若是此文件不存在,sqlite 會自動創建它。若是它存在,就嘗試把它當數據庫文件來打開。sqlite3 ** 參數即前面提到的關鍵數據結構。這個結構底層細節如何,你不要關它。函數返回值表示操做是否正確,若是是 SQLITE_OK 則表示操做正常。相關的返回值sqlite定義了一些宏。具體這些宏的含義能夠參考 sqlite3.h 文件。裏面有詳細定義(順便說一下,sqlite3 的代碼註釋率自稱是很是高的,實際上也的確很高。只要你會看英文,sqlite 可讓你學到很多東西)。下面介紹關閉數據庫後,再給一段參考代碼。i.3 關閉數據庫int sqlite3_close(sqlite3 *); 前面若是用 sqlite3_open 開啓了一個數據庫,結尾時不要忘了用這個函數關閉數據庫。下面給段簡單的代碼:extern "C"
{
#include "./sqlite3.h"
};int main( int , char** )
{
sqlite3 * db = NULL; //聲明sqlite關鍵結構指針
int result;//打開數據庫//須要傳入 db 這個指針的指針,由於 sqlite3_open 函數要爲這個指針分配內存,還要讓db指針指向這個內存區 result = sqlite3_open( 「c:\\Dcg_database.db」, &db );
if( result != SQLITE_OK )
{
//數據庫打開失敗
return -1;
}
//數據庫操做代碼
//數據庫打開成功
//關閉數據庫
sqlite3_close( db );return 0;
}這就是一次數據庫操做過程。
(2) SQL語句操做本節介紹如何用sqlite 執行標準 sql 語法。
i.1 執行sql語句int sqlite3_exec(sqlite3*, const char *sql, sqlite3_callback, void *, char **errmsg );這就是執行一條 sql 語句的函數。第1個參數再也不說了,是前面open函數獲得的指針。說了是關鍵數據結構。第2個參數const char *sql 是一條 sql 語句,以\0結尾。第3個參數sqlite3_callback 是回調,當這條語句執行以後,sqlite3會去調用你提供的這個函數。(什麼是回調函數,本身找別的資料學習)第4個參數void * 是你所提供的指針,你能夠傳遞任何一個指針參數到這裏,這個參數最終會傳到回調函數裏面,若是不須要傳遞指針給回調函數,能夠填NULL。等下咱們再看回調函數的寫法,以及這個參數的使用。第5個參數char ** errmsg 是錯誤信息。注意是指針的指針。sqlite3裏面有不少固定的錯誤信息。執行 sqlite3_exec 以後,執行失敗時能夠查閱這個指針(直接 printf(「%s\n」,errmsg))獲得一串字符串信息,這串信息告訴你錯在什麼地方。sqlite3_exec函數經過修改你傳入的指針的指針,把你提供的指針指向錯誤提示信息,這樣sqlite3_exec函數外面就能夠經過這個 char*獲得具體錯誤提示。說明:一般,sqlite3_callback 和它後面的 void * 這兩個位置均可以填 NULL。填NULL表示你不須要回調。好比你作 insert 操做,作 delete 操做,就沒有必要使用回調。而當你作 select 時,就要使用回調,由於 sqlite3 把數據查出來,得經過回調告訴你查出了什麼數據。
i.2 exec 的回調typedef int (*sqlite3_callback)(void*,int,char**, char**);你的回調函數必須定義成上面這個函數的類型。下面給個簡單的例子://sqlite3的回調函數 // sqlite 每查到一條記錄,就調用一次這個回調
int LoadMyInfo( void * para, int n_column, char ** column_value, char ** column_name )
{
//para是你在 sqlite3_exec 裏傳入的 void * 參數 //經過para參數,你能夠傳入一些特殊的指針(好比類指針、結構指針),而後在這裏面強制轉換成對應的類型(這裏面是void*類型,必須強制轉換成你的類型纔可用)。而後操做這些數據 //n_column是這一條記錄有多少個字段 (即這條記錄有多少列) // char ** column_value 是個關鍵值,查出來的數據都保存在這裏,它其實是個1維數組(不要覺得是2維數組),每個元素都是一個 char * 值,是一個字段內容(用字符串來表示,以\0結尾) //char ** column_name 跟 column_value是對應的,表示這個字段的字段名稱
//這裏,我不使用 para 參數。忽略它的存在. int i;printf( 「記錄包含 %d 個字段\n」, n_column );for( i = 0 ; i < n_column; i ++ )
{
printf( 「字段名:%s ?> 字段值:%s\n」, column_name[i], column_value[i] );
}printf( 「------------------\n「 ); return 0;
}
int main( int , char ** )
{
sqlite3 * db;
int result;
char * errmsg = NULL; result = sqlite3_open( 「c:\\Dcg_database.db」, &db );
if( result != SQLITE_OK )
{
//數據庫打開失敗
return -1;
}//數據庫操做代碼
//建立一個測試表,表名叫 MyTable_1,有2個字段: ID 和 name。其中ID是一個自動增長的類型,之後insert時能夠不去指定這個字段,它會本身從0開始增長
result = sqlite3_exec( db, 「create table MyTable_1( ID integer primary key autoincrement, name nvarchar(32) )」, NULL, NULL, errmsg );
if(result != SQLITE_OK )
{
printf( 「建立表失敗,錯誤碼:%d,錯誤緣由:%s\n」, result, errmsg );
}
//插入一些記錄
result = sqlite3_exec( db, 「insert into MyTable_1( name ) values ( ‘走路’ )」, 0, 0, errmsg );
if(result != SQLITE_OK )
{
printf( 「插入記錄失敗,錯誤碼:%d,錯誤緣由:%s\n」, result, errmsg );
}//開始查詢數據庫result = sqlite3_exec( db, 「select * from MyTable_1」, LoadMyInfo, NULL, errmsg );//關閉數據庫sqlite3_close( db );return 0;
}
經過上面的例子,應該能夠知道如何打開一個數據庫,如何作數據庫基本操做。有這些知識,基本上能夠應付不少數據庫操做了。i.3 不使用回調查詢數據庫上面介紹的 sqlite3_exec 是使用回調來執行 select 操做。還有一個方法能夠直接查詢而不須要回調。可是,我我的感受仍是回調好,由於代碼能夠更加整齊,只不過用回調很麻煩,你得聲明一個函數,若是這個函數是類成員函數,你還不得不把它聲明成 static 的(要問爲何?這又是C++基礎了。C++成員函數實際上隱藏了一個參數:this,C++調用類的成員函數的時候,隱含把類指針當成函數的第一個參數傳遞進去。結果,這形成跟前面說的 sqlite 回調函數的參數不相符。只有當把成員函數聲明成 static 時,它纔沒有多餘的隱含的this參數)。雖然回調顯得代碼整齊,但有時候你仍是想要非回調的 select 查詢。這能夠經過 sqlite3_get_table 函數作到。int sqlite3_get_table(sqlite3*, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg );第1個參數再也不多說,看前面的例子。第2個參數是 sql 語句,跟 sqlite3_exec 裏的 sql 是同樣的。是一個很普通的以\0結尾的char *字符串。第3個參數是查詢結果,它依然一維數組(不要覺得是二維數組,更不要覺得是三維數組)。它內存佈局是:第一行是字段名稱,後面是緊接着是每一個字段的值。下面用例子來講事。第4個參數是查詢出多少條記錄(即查出多少行)。第5個參數是多少個字段(多少列)。第6個參數是錯誤信息,跟前面同樣,這裏很少說了。下面給個簡單例子:int main( int , char ** )
{
sqlite3 * db;
int result;
char * errmsg = NULL; char **dbResult; //是 char ** 類型,兩個*號 int nRow, nColumn; int i , j; int index; result = sqlite3_open( 「c:\\Dcg_database.db」, &db );
if( result != SQLITE_OK )
{
//數據庫打開失敗
return -1;
}//數據庫操做代碼//假設前面已經建立了 MyTable_1 表//開始查詢,傳入的 dbResult 已是 char **,這裏又加了一個 & 取地址符,傳遞進去的就成了 char ***result = sqlite3_get_table( db, 「select * from MyTable_1」, &dbResult, &nRow, &nColumn, &errmsg );if( SQLITE_OK == result )
{
//查詢成功
index = nColumn; //前面說過 dbResult 前面第一行數據是字段名稱,從 nColumn 索引開始纔是真正的數據
printf( 「查到%d條記錄\n」, nRow ); for( i = 0; i < nRow ; i++ )
{
printf( 「第 %d 條記錄\n」, i+1 );
for( j = 0 ; j < nColumn; j++ )
{
printf( 「字段名:%s ?> 字段值:%s\n」, dbResult[j], dbResult [index] );
++index; // dbResult 的字段值是連續的,從第0索引到第 nColumn - 1索引都是字段名稱,從第 nColumn 索引開始,後面都是字段值,它把一個二維的表(傳統的行列表示法)用一個扁平的形式來表示
}
printf( 「-------\n」 ); }
}//到這裏,不論數據庫查詢是否成功,都釋放 char** 查詢結果,使用 sqlite 提供的功能來釋放
sqlite3_free_table( dbResult );
//關閉數據庫
sqlite3_close( db );return 0;
}
到這個例子爲止,sqlite3 的經常使用用法都介紹完了。用以上的方法,再配上 sql 語句,徹底能夠應付絕大多數數據庫需求。但有一種狀況,用上面方法是沒法實現的:須要insert、select 二進制。當須要處理二進制數據時,上面的方法就沒辦法作到。下面這一節說明如何插入二進制數據
(2) 操做二進制sqlite 操做二進制數據須要用一個輔助的數據類型:sqlite3_stmt * 。這個數據類型記錄了一個「sql語句」。爲何我把 「sql語句」 用雙引號引發來?由於你能夠把 sqlite3_stmt * 所表示的內容當作是 sql語句,可是實際上它不是咱們所熟知的sql語句。它是一個已經把sql語句解析了的、用sqlite本身標記記錄的內部數據結構。正由於這個結構已經被解析了,因此你能夠往這個語句裏插入二進制數據。固然,把二進制數據插到 sqlite3_stmt 結構裏可不能直接 memcpy ,也不能像 std::string 那樣用 + 號。必須用 sqlite 提供的函數來插入。
i.1 寫入二進制下面說寫二進制的步驟。要插入二進制,前提是這個表的字段的類型是 blob 類型。我假設有這麼一張表:create table Tbl_2( ID integer, file_content blob )首先聲明sqlite3_stmt * stat;而後,把一個 sql 語句解析到 stat 結構裏去:sqlite3_prepare( db, 「insert into Tbl_2( ID, file_content) values( 10, ? )」, -1, &stat, 0 );上面的函數完成 sql 語句的解析。第一個參數跟前面同樣,是個 sqlite3 * 類型變量,第二個參數是一個 sql 語句。這個 sql 語句特別之處在於 values 裏面有個 ? 號。在sqlite3_prepare函數裏,?號表示一個未定的值,它的值等下才插入。第三個參數我寫的是-1,這個參數含義是前面 sql 語句的長度。若是小於0,sqlite會自動計算它的長度(把sql語句當成以\0結尾的字符串)。第四個參數是 sqlite3_stmt 的指針的指針。解析之後的sql語句就放在這個結構裏。第五個參數我也不知道是幹什麼的。爲0就能夠了。若是這個函數執行成功(返回值是 SQLITE_OK 且 stat 不爲NULL ),那麼下面就能夠開始插入二進制數據。sqlite3_bind_blob( stat, 1, pdata, (int)(length_of_data_in_bytes), NULL ); // pdata爲數據緩衝區,length_of_data_in_bytes爲數據大小,以字節爲單位這個函數一共有5個參數。第1個參數:是前面prepare獲得的 sqlite3_stmt * 類型變量。第2個參數:?號的索引。前面prepare的sql語句裏有一個?號,假若有多個?號怎麼插入?方法就是改變 bind_blob 函數第2個參數。這個參數我寫1,表示這裏插入的值要替換 stat 的第一個?號(這裏的索引從1開始計數,而非從0開始)。若是你有多個?號,就寫多個 bind_blob 語句,並改變它們的第2個參數就替換到不一樣的?號。若是有?號沒有替換,sqlite爲它取值null。第3個參數:二進制數據起始指針。第4個參數:二進制數據的長度,以字節爲單位。第5個參數:是個析夠回調函數,告訴sqlite當把數據處理完後調用此函數來析夠你的數據。這個參數我尚未使用過,所以理解也不深入。可是通常都填NULL,須要釋放的內存本身用代碼來釋放。bind完了以後,二進制數據就進入了你的「sql語句」裏了。你如今能夠把它保存到數據庫裏:int result = sqlite3_step( stat );經過這個語句,stat 表示的sql語句就被寫到了數據庫裏。最後,要把 sqlite3_stmt 結構給釋放:sqlite3_finalize( stat ); //把剛纔分配的內容析構掉 i.2 讀出二進制下面說讀二進制的步驟。跟前面同樣,先聲明 sqlite3_stmt * 類型變量:sqlite3_stmt * stat;而後,把一個 sql 語句解析到 stat 結構裏去:sqlite3_prepare( db, 「select * from Tbl_2」, -1, &stat, 0 );當 prepare 成功以後(返回值是 SQLITE_OK ),開始查詢數據。int result = sqlite3_step( stat );這一句的返回值是 SQLITE_ROW 時表示成功(不是 SQLITE_OK )。你能夠循環執行 sqlite3_step 函數,一次 step 查詢出一條記錄。直到返回值不爲 SQLITE_ROW 時表示查詢結束。而後開始獲取第一個字段:ID 的值。ID是個整數,用下面這個語句獲取它的值:int id = sqlite3_column_int( stat, 0 ); //第2個參數表示獲取第幾個字段內容,從0開始計算,由於個人表的ID字段是第一個字段,所以這裏我填0 下面開始獲取 file_content 的值,由於 file_content 是二進制,所以我須要獲得它的指針,還有它的長度: const void * pFileContent = sqlite3_column_blob( stat, 1 ); int len = sqlite3_column_bytes( stat, 1 );這樣就獲得了二進制的值。把 pFileContent 的內容保存出來以後,不要忘了釋放 sqlite3_stmt 結構:sqlite3_finalize( stat ); //把剛纔分配的內容析構掉 i.3 重複使用 sqlite3_stmt 結構若是你須要重複使用 sqlite3_prepare 解析好的 sqlite3_stmt 結構,須要用函數: sqlite3_reset。result = sqlite3_reset(stat);這樣, stat 結構又成爲 sqlite3_prepare 完成時的狀態,你能夠從新爲它 bind 內容。
(4) 事務處理sqlite 是支持事務處理的。若是你知道你要同步刪除不少數據,不仿把它們作成一個統一的事務。一般一次 sqlite3_exec 就是一次事務,若是你要刪除1萬條數據,sqlite就作了1萬次:開始新事務->刪除一條數據->提交事務->開始新事務->… 的過程。這個操做是很慢的。由於時間都花在了開始事務、提交事務上。你能夠把這些同類操做作成一個事務,這樣若是操做錯誤,還可以回滾事務。事務的操做沒有特別的接口函數,它就是一個普通的 sql 語句而已:分別以下:int result;result = sqlite3_exec( db, "begin transaction", 0, 0, &zErrorMsg ); //開始一個事務result = sqlite3_exec( db, "commit transaction", 0, 0, &zErrorMsg ); //提交事務result = sqlite3_exec( db, "rollback transaction", 0, 0, &zErrorMsg ); //回滾事務
----------------------------------------------------------#include <stdio.h>02 #include <sqlite3.h>03 04 static int callback(void *NotUsed, int argc, char **argv, char **azColName){05 int i;06 for(i=0; i<argc; i++){07 printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");08 }09 printf("\n");10 return 0;11 }12 13 int main(int argc, char **argv){14 sqlite3 *db;15 char *zErrMsg = 0;16 int rc;17 18 if( argc!=3 ){19 fprintf(stderr, "Usage: %s DATABASE SQL-STATEMENT\n", argv[0]);20 exit(1);21 }22 rc = sqlite3_open(argv[1], &db);23 if( rc ){24 fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));25 sqlite3_close(db);26 exit(1);27 }28 rc = sqlite3_exec(db, argv[2], callback, 0, &zErrMsg);29 if( rc!=SQLITE_OK ){30 fprintf(stderr, "SQL error: %s\n", zErrMsg);31 sqlite3_free(zErrMsg);32 }33 sqlite3_close(db);34 return 0;35 }