前言
SQLite3是SQLite一個全新的版本,它雖然是在SQLite2的代碼基礎之上開發的,但是使用了和之前的版本不兼容的數據庫格式和API。SQLite3是為了滿足以下的需求而開發的:支持UTF-16編碼、用戶自定義的文本比較方法、可以對BLOBs字段建立索引。SQLite 3.X版的和SQLite 2.X版的API非常相似,但是有一些重要的改變需要注意。3.X版的API增加到超過185個,所有API接口函數和數據結構的前綴都由"sqlite_"改為了"sqlite3_",這是為了避免同時使用SQLite 2.X和SQLite 3.X這兩個版本的時候發生鏈接沖突。這里概要地介紹一下SQLite的核心API,詳細的API指南參考http://sqlite.com/capi3ref.html。
由於對於C語言應用什么數據類型來存放UTF-16編碼的字符串並沒有一致的規范,因此SQLite使用了普通的void*類型來指向UTF-16編碼的字符串。客戶端使用過程中可以把void*映射成適合他們的系統的任何數據類型。
一個SQL數據庫引擎的首要任務是執行SQL語句以獲得我們想要的數據。為了完成這個任務,開發需要知道兩個對象:數據庫連接對象sqlite3和SQL預處理語句對象sqlite3_stmt,定義如下:
typedef struct sqlite3 sqlite3;
typedef struct sqlite3_stmt sqlite3_stmt;
嚴格地說,SQL預處理語句對象不是必需的,因為有使用方便的包裝函數sqlite3_exec或sqlite3_get_table,它們封裝並且隱藏了SQL語句對象。不過理解SQL語句對象能更好地使用SQLite。
數據庫連接對象和SQL語句對象由下面幾個核心的C/C++接口來控制:sqlite3_open()、sqlite3_prepare()、sqlite3_step()、sqlite3_column()、sqlite3_finalize()、sqlite3_close()。
使用SQLite3時根據以上函數大概分為幾個過程,這幾個過程是概念上的說法,而不完全是程序運行的過程,如sqlite3_column()表示的是對查詢獲得一行里面的數據的列的各個操作統稱,實際上在sqlite中並不存在這個函數。在SQLite提供的C/C++接口中,其中5個API屬於核心接口。相比於其它數據庫引擎提供的API,如OCI、MySQL API等,SQLite提供的接口易於理解和掌握。以上六個C/C++接口及上面的兩個對象構成SQLite的核心功能。注意這些接口有些有多個版本,例如sqlite3_open()有三個獨立的版本:sqlite3_open(), sqlite3_open16()和sqlite3_open_v2(),它們以稍微不同的方式完成同樣的事情。sqlite3_column()代表一個家族系列:sqlite_column_int(), sqlite_column_blob()等等,用於提取結果集中各種類型的列數據。
核心對象和接口:
1. 核心對象:
在SQLite中最主要的兩個對象是:database_connection和prepared_statement。database_connection對象是由sqlite3_open()接口函數創建並返回的,在應用程序使用任何其他SQLite接口函數之前,必須先調用該函數以便獲得database_connnection對象,在隨后的其他API調用中,都需要該對象作為輸入參數以完成相應的工作。至於prepare_statement,我們可以簡單地將它視為編譯后的SQL語句,因此,所有和SQL語句執行相關的函數也都需要該對象作為輸入參數以完成指定的SQL操作。
2. 核心接口:
1). sqlite3_open
上面已經提到過這個函數了,它是操作SQLite數據庫的入口函數。該函數返回的database_connection對象是很多其他SQLite API的句柄參數。注意,我們通過該函數既可以打開已經存在的數據庫文件,也可以創建新的數據庫文件。對於該函數返回的database_connection對象,我們可以在多個線程之間共享該對象的指針,以便完成和數據庫相關的任意操作。然而在多線程情況下,更為推薦的使用方式是,為每個線程創建獨立的database_connection對象。對於該函數還有一點也需額外說明,我們沒有必要為了訪問多個數據庫而創建多個數據庫連接對象,因為通過SQLite自帶的ATTACH命令可以在一個連接中方便的訪問多個數據庫。
2). sqlite3_prepare
該函數將SQL文本轉換為prepared_statement對象,並在函數執行后返回該對象的指針。事實上,該函數並不會評估參數指定SQL語句,它僅僅是將SQL文本初始化為待執行的狀態。最后需要指出的,對於新的應用程序,可以使用sqlite3_prepare_v2接口函數來替代該函數以完成相同的工作。
3). sqlite3_step
該函數用於評估sqlite3_prepare函數返回的prepared_statement對象,在執行完該函數之后,prepared_statement對象的內部指針將指向其返回的結果集的第一行。如果打算進一步迭代其后的數據行,就需要不斷的調用該函數,直到所有的數據行都遍歷完畢。然而對於INSERT、UPDATE和DELETE等DML語句,該函數執行一次即可完成。
4). sqlite3_column
該函數用於獲取當前行指定列的數據,然而嚴格意義上講,此函數在SQLite的接口函數中並不存在,而是由一組相關的接口函數來完成該功能,其中每個函數都返回不同類型的數據,如:
sqlite3_column_blob
sqlite3_column_bytes
sqlite3_column_bytes16
sqlite3_column_double
sqlite3_column_int
sqlite3_column_int64
sqlite3_column_text
sqlite3_column_text16
sqlite3_column_type
sqlite3_column_value
sqlite3_column_count
其中,sqlite3_column_count函數用於獲取當前結果集中的字段數目。下面是使用sqlite3_step和sqlite3_column函數迭代結果集中每行數據的偽代碼(注意這里作為示例代碼簡化了對字段類型的判斷):
int fieldCount = sqlite3_column_count(...); while (sqlite3_step(...) <> EOF) { for (int i = 0; i < fieldCount; ++i) { int v = sqlite3_column_int(...,i); } }
5). sqlite3_finalize
該函數用於銷毀prepared statement對象,否則將會造成內存泄露。
6). sqlite3_close
該函數用於關閉之前打開的database_connection對象,其中所有和該對象相關的prepared_statements對象都必須在此之前先被銷毀。
參數綁定:
和大多數關系型數據庫一樣,SQLite的SQL文本也支持變量綁定,以便減少SQL語句被動態解析的次數,從而提高數據查詢和數據操作的效率。要完成該操作,我們需要使用SQLite提供的另外兩個接口API,sqlite3_reset和sqlite3_bind。見如下示例:
void test_parameter_binding() { //1. 不帶參數綁定的情況下插入多條數據。 char strSQL[128]; for (int i = 0; i < MAX_ROWS; ++i) { sprintf(strSQL,"insert into testtable values(%d)",i); sqlite3_prepare_v2(..., strSQL); sqlite3_step(prepared_stmt); sqlite3_finalize(prepared_stmt); } //2. 參數綁定的情況下插入多條數據。 string strSQLWithParameter = "insert into testtable values(?)"; sqlite3_prepare_v2(..., strSQLWithParameter); for (int i = 0; i < MAX_ROWS; ++i) { sqlite3_bind(...,i); sqlite3_step(prepared_stmt); sqlite3_reset(prepared_stmt); } sqlite3_finalize(prepared_stmt); }
這里首先需要說明的是,SQL語句"insert into testtable values(?)"中的問號(?)表示參數變量的占位符,該規則在很多關系型數據庫中都是一致的,因此這對於數據庫移植操作還是比較方便的。
通過上面的示例代碼,明顯可以看出參數綁定寫法的執行效率要高於每次生成不同的SQL語句的寫法,即(2)在效率上要明顯優於(1),下面是針對這兩種寫法的具體比較:
1.單單從程序表面來看,前者在for循環中執行了更多的任務,比如字符串的填充、SQL語句的prepare,以及prepared_statement對象的釋放。
2.在SQLite的官方文檔中明確的指出,sqlite3_prepare_v2的執行效率往往要低於sqlite3_step的效率。
3.當插入的數據量較大時,后者帶來的效率提升還是相當可觀的。
一、打開和關閉數據庫連接
int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); int sqlite3_open16( const void *filename, /* Database filename (UTF-16) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); int sqlite3_open_v2( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb, /* OUT: SQLite db handle */ int flags, /* Flags */ const char *zVfs /* Name of VFS module to use */ ); int sqlite3_close(sqlite3*); int sqlite3_close_v2(sqlite3*); int sqlite3_errcode(sqlite3 *db); int sqlite3_extended_errcode(sqlite3 *db); const char *sqlite3_errmsg(sqlite3*); const void *sqlite3_errmsg16(sqlite3*);
建立到一個SQLite數據庫文件的連接,返回連接對象。如果數據庫文件不存在,則創建這個文件,函數返回一個整數錯誤代碼。許多SQLite接口需要一個指向連接對象的指針作為第一個參數,這個函數用來創建一個數據庫連接對象。sqlite3_open()和sqlite3_open16()的不同之處在於sqlite3_open16()使用UTF-16編碼(使用本地主機字節順序)傳遞數據庫文件名。如果要創建新數據庫,sqlite3_open16()將內部文本轉換為UTF-16編碼,反之sqlite3_open()將文本轉換為UTF-8編碼。打開或者創建數據庫的命令會被緩存,直到這個數據庫真正被調用的時候才會被執行。而且允許使用PRAGMA聲明來設置如本地文本編碼或默認內存頁面大小等選項和參數。
sqlite3_close()關閉數據庫連接,在關閉之前所有准備好的SQL語句對象都要被銷毀。
sqlite3_errcode()通常用來獲取最近調用的API接口返回的錯誤代碼。sqlite3_errmsg()則用來得到這些錯誤代碼所對應的文字說明。這些錯誤信息將以UTF-8的編碼返回,並且在下一次調用任何SQLiteAPI函數的時候被清除。sqlite3_errmsg16()和sqlite3_errmsg()大體上相同,除了返回的錯誤信息將以UTF-16本機字節順序編碼。
SQLite的返回碼定義如下:
#define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ #define SQLITE_ERROR 1 /* SQL error or missing database */ #define SQLITE_INTERNAL 2 /* 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 sqlite3_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 /* Unknown opcode in sqlite3_file_control() */ #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 /* Database is empty */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint 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_FORMAT 24 /* Auxiliary database format error */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ /* end-of-error-codes */
二、編譯SQL語句
int sqlite3_prepare( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); int sqlite3_prepare_v2( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); int sqlite3_prepare16( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); int sqlite3_prepare16_v2( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ );
把SQL文本編譯成一個SQL語句對象並返回這個對象的指針。它只是把含有SQL語句的字符串編譯成字節碼,並不執行SQL語句。sqlite3_prepare()處理的SQL語句應該是UTF-8編碼的,而sqlite3_prepare16()則要求是UTF-16編碼的。輸入的參數中只有第一個SQL語句會被編譯。第四個參數則用來指向輸入參數中下一個需要編譯的SQL語句存放的SQLite statement對象的指針。任何時候如果調用sqlite3_finalize()將銷毀一個准備好的SQL聲明。在數據庫關閉之前,所有准備好的聲明都必須被釋放銷毀。sqlite3_reset()函數用來重置一個SQL聲明的狀態,使得它可以被再次執行。
注意現在sqlite3_prepare()已經不被推薦使用了,在新的應用中推薦使用sqlite3_prepare_v2()。
三、執行SQL語句
int sqlite3_step(sqlite3_stmt*);
在SQL聲明准備好之后,就可以調用sqlite3_step()來執行這個SQL聲明。如果SQL返回了一個單行結果集,sqlite3_step()函數將返回SQLITE_ROW,若要得到結果集的第二行、第三行 ...,則要繼續調用sqlite3_step()。如果SQL語句執行成功或者正常將返回SQLITE_DONE,否則將返回錯誤代碼。如果不能打開數據庫文件則會返回SQLITE_BUSY。
執行SQL語句還可以直接用便捷的包裝函數,這樣就無需預先編譯SQL語句。如下:
typedef int (*sqlite3_callback)(void*,int,char**, char**); int sqlite3_exec( sqlite3*, /* An open database */ const char *sql, /* SQL to be evaluated */ int (*callback)(void*,int,char**,char**), /* Callback function */ void *, /* 1st argument to callback */ char **errmsg /* Error msg written here */ );
sqlite3_exec函數依然像它在SQLite 2中一樣承擔着很多的工作。該函數的第二個參數中可以指定零個或多個SQL語句,查詢的結果返回給回調函數,回調函數會作用在結果集的每條記錄上。sqlite3_exec函數實際上封裝了sqlite3_prepare_v2(),sqlite3_step()和sqlite3_finalize(),因此可以通過一個調用直接執行多條SQL語句,讓應用程序省略大量代碼,因此在實際應用中一般使用這個函數。
四、獲取結果集數據
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); 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); sqlite3_int64 sqlite3_column_int64(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_value *sqlite3_column_value(sqlite3_stmt*, int iCol); const char *sqlite3_column_name(sqlite3_stmt*, int N); const void *sqlite3_column_name16(sqlite3_stmt*, int N); int sqlite3_column_count(sqlite3_stmt *pStmt); int sqlite3_data_count(sqlite3_stmt *pStmt);
如果函數sqlite3_step()的返回值是SQLITE_ROW,那么用以上方法可以獲得記錄集中的數據。
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編碼的BLOB列的字節數或者TEXT字符串的字節數。sqlite3_column_bytes16()對於BLOB列返回同樣的結果,但是對於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()接口返回的數據類型來獲取數據,數據類型不同時軟件將自動轉換。
五、SQL聲明對象的銷毀和重用
int sqlite3_finalize(sqlite3_stmt*); int sqlite3_reset(sqlite3_stmt*);
函數sqlite3_finalize()銷毀由sqlite3_prepare()創建的SQL聲明對象。在數據庫關閉之前每個准備好的聲明都必須被銷毀,以避免內存泄露。sqlite3_reset()則用來重置一個SQL聲明的狀態,使得它可以被再次執行。例如用sqlite3_step()執行完編譯好的SQL聲明后,還想再執行它,則可用sqlite3_reset()重置它即可,而無需用sqlite3_prepare()再來編譯一個新SQL聲明,因為很多SQL聲明的編譯時間甚至超過執行時間。
六、給SQl語句綁定參數
SQL語句聲明中可以包含如下形式的參數:
?
?NNN
:AAA
$AAA
@AAA
其中"NNN"是一個整數,"AAA"是一個字符串,這些標記代表一些不確定的字符值(或者說是通配符)。在首次調用sqlite3_step()之前或者剛調用sqlite3_reset()之后,應用程序可以用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, 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);
以上是sqlite3_bind所包含的全部接口,用來給SQL聲明中的通配符賦值。沒有綁定的通配符則被認為是空值。已綁定的值不會被sqlite3_reset()函數重置。但是在調用了sqlite3_reset()之后所有的通配符都可以被重新賦值。注意綁定操作是可選的。
七、擴展SQL
(1)創建自定義的比較序列:
int sqlite3_create_collation( sqlite3*, const char *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); int sqlite3_create_collation_v2( sqlite3*, const char *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*), void(*xDestroy)(void*) ); int sqlite3_create_collation16( sqlite3*, const void *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); int sqlite3_collation_needed( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const char*) ); int sqlite3_collation_needed16( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const void*) );
這些函數在數據庫連接上,為要比較的文本添加、刪除或者修改自定義比較規則。第三個參數eTextRep表示SQLite支持的字符編碼類型,必須是以下常量之一:
#define SQLITE_UTF8 1 #define SQLITE_UTF16LE 2 #define SQLITE_UTF16BE 3 #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* sqlite3_create_function only */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
sqlite3_create_collation()函數用來聲明一個比較序列和實現它的比較函數,比較函數只能用來做文本的比較。同一個自定義的比較規則的同一個比較函數可以有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編碼。
(2)創建自定義的SQL函數:
int sqlite3_create_function( sqlite3 *db, const char *zFunctionName, int nArg, int eTextRep, void *pApp, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); int sqlite3_create_function16( sqlite3 *db, const void *zFunctionName, int nArg, int eTextRep, void *pApp, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); int sqlite3_create_function_v2( sqlite3 *db, const char *zFunctionName, int nArg, int eTextRep, void *pApp, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*) );
nArg參數用來表明自定義函數的參數個數。如果參數值為0,則表示接受任意個數的參數。用eTextRep參數來表明傳入參數的編碼形式。SQLite 3允許同一個自定義函數有多種不同的編碼參數的版本。數據庫引擎會自動選擇轉換參數編碼個數最少的版本使用。
普通的函數只需要設置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結構體中提取數據,以獲得SQL函數的參數值:
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*); sqlite3_int64 sqlite3_value_int64(sqlite3_value*); const unsigned char *sqlite3_value_text(sqlite3_value*); const void *sqlite3_value_text16(sqlite3_value*); const void *sqlite3_value_text16le(sqlite3_value*); const void *sqlite3_value_text16be(sqlite3_value*); int sqlite3_value_type(sqlite3_value*); int sqlite3_value_numeric_type(sqlite3_value*);
上面的函數調用以下的API來獲得上下文內容和返回結果:
void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); void sqlite3_result_blob(sqlite3_context*, const void*, int, 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_error_toobig(sqlite3_context*); void sqlite3_result_error_nomem(sqlite3_context*); void sqlite3_result_error_code(sqlite3_context*, int); void sqlite3_result_int(sqlite3_context*, int); void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); void sqlite3_result_null(sqlite3_context*); void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); void sqlite3_result_value(sqlite3_context*, sqlite3_value*); void sqlite3_result_zeroblob(sqlite3_context*, int n); void *sqlite3_user_data(sqlite3_context*); void *sqlite3_get_auxdata(sqlite3_context*, int N); void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
(3)注冊自定義的虛擬表模塊:
int sqlite3_create_module( sqlite3 *db, /* SQLite connection to register module with */ const char *zName, /* Name of the module */ const sqlite3_module *p, /* Methods for the module */ void *pClientData /* Client data for xCreate/xConnect */ ); int sqlite3_create_module_v2( sqlite3 *db, /* SQLite connection to register module with */ const char *zName, /* Name of the module */ const sqlite3_module *p, /* Methods for the module */ void *pClientData, /* Client data for xCreate/xConnect */ void(*xDestroy)(void*) /* Module destructor function */ );
其中第二個參數指定虛擬表模塊名稱,第三個參數指向虛擬表模塊,第四個參數為傳給虛擬表模塊xCreate/xConnect方法的客戶數據。sqlite3_create_module_v2()還有第五個參數,指定對pClientData數據進行析構的函數。若指定析構函數為NULL,則該函數與sqlite3_create_module()等價。
SQLite的所有內建SQL函數都使用上面這些接口來創建,特別是date.c和func.c中的SQL函數代碼。
程序示例
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sqlite3.h> int main( int argc, char **argv ) { sqlite3 *db; sqlite3_stmt * stmt; const char *zTail; //打開數據庫 int r = sqlite3_open("mysqlite.db",&db); if(r){ printf("%s",sqlite3_errmsg(db)); } else printf("open db sccess!\n"); //創建Table //sqlite3_prepare()將SQL語句編譯為sqlite內部一個結構體(sqlite3_stmt), //該結構體中包含了將要執行的SQL語句的信息 //第四個參數用來指向輸入參數中下一個需要編譯的SQL語句存放的 SQLite statement 對象的指針 sqlite3_prepare(db,"CREATE TABLE players ( ID INTEGER PRIMARY KEY, name TEXT, age INTEGER);",-1,&stmt,&zTail); printf("prepared has done\n"); //調用sqlite3_step(),此時SQL語句才真正執行,執行成功,返回SQLITE_DONE或SQLITE_ROW. //每次調用sqlite3_step(),只返回一行數據,使用sqlite3_column_XXX()函數來取出這些數據 //要取出全部的數據,則需要反復調用sqlite3_step() sqlite3_step(stmt); //調用sqlite3_finalize(),釋放stmt占用的內存,該內存是在sqlite3_prepare()時分配的 //如果SQL語句要重復使用,可以調用sqlite3_reset()來清除已經綁定的參數 sqlite3_finalize(stmt); printf("create table success!\n"); //插入數據 sqlite3_prepare(db,"INSERT INTO players (name,age) VALUES(?,?);",-1,&stmt,&zTail); char str[] = "Kevin"; int n = 23; //sqlite3_bind_xxx的第四個參數為負,則字符串長度由第一個0終止的位數決定 //SQLITE_STATIC表示命令執行完后的信息為static類型,不能被改動,而且不需要被free sqlite3_bind_text(stmt,1,str,-1,SQLITE_STATIC); sqlite3_bind_int(stmt,2,n); r = sqlite3_step(stmt); if( r!=SQLITE_DONE){ printf("%s",sqlite3_errmsg(db)); } //清除已經綁定的參數 sqlite3_reset(stmt); //插入第二個數據 char str2[] = "Jack"; int n2 = 16; sqlite3_bind_text(stmt,1,str2,-1,SQLITE_STATIC); sqlite3_bind_int(stmt,2,n2); r = sqlite3_step(stmt); if( r!=SQLITE_DONE){ printf("%s",sqlite3_errmsg(db)); } sqlite3_finalize(stmt); //釋放stmt所占的內存 //查詢所有數據 sqlite3_prepare(db,"SELECT ID, name, age FROM players ORDER BY age",-1,&stmt,&zTail); r = sqlite3_step(stmt); int number; int id; const unsigned char * name; while( r == SQLITE_ROW ){ id = sqlite3_column_int( stmt, 0 ); name = sqlite3_column_text( stmt,1 ); number = sqlite3_column_int( stmt, 2 ); printf("ID: %d Name: %s Age: %d \n",id,name,number); sleep(1); r = sqlite3_step(stmt); } sqlite3_finalize(stmt); //關閉數據庫 sqlite3_close(db); return 0; } 編譯運行: $ gcc sqlite.c –o sqlite –lsqlite3 $ ./sqlite