SQLite 中 C/C++ 介面介紹

Cocoabit發表於2014-11-05

這篇文章簡要的介紹了 SQLite 的 C/C++ 介面。

早期版本的 SQLite 很好學是因為他們只提供了 5 個 C/C++ 的介面。但是隨著 SQLite 功能的增加,新的 C/C++ 介面加入,現在已經有超過 200 個不同的 API 了。這對新人可能是一種阻礙。幸運的是,大部分的 C/C++ 介面都是有特殊用途的,不需要了解。儘管有這麼多的入口點,核心的 API 還是相當的簡單而且容易使用。這篇文章旨在提供所有能使讀者容易理解 SQLite 如何工作的背景資訊。

一個獨立的介面文件提供了 SQLite 不同的 C/C++ 介面的詳細說明。一旦讀者理解了操作 SQLite 的基本概念,該文件就可以成為參考手冊了。這篇文章只是一個介紹,不會是 SQLite 的完整、權威的參考手冊。

1.0 核心物件和介面

SQL 資料庫引擎的核心任務是計算 SQL 語句的值(evaluate statements of SQL)。為了完成這個目的,開發者需要了解兩個物件:

資料庫連線物件(The database connection object):sqlite3
預處理好的語句物件(The prepared statement object): sqlite3_stmt

嚴格來講,對於一些封裝好的便捷介面 prepared statement object不是必須的,比如sqlite3_exec 還有 sqlite3_get_table, 在內部求值時都會封裝並隱藏這些 prepared statement object。然而,要想充分利用 SQLite, 理解 prepared statements 還是有必要的。

Database connection 和 prepared statement 物件由下面列出的一組 C/C++ 介面(interface routine)控制。

sqlite3_open()  
sqlite3_prepare()  
sqlite3_step()  
sqlite3_column()  
sqlite3_finalize()  
sqlite3_close()

上面列出的 6 個 C/C++ 介面還有兩個物件組成了 SQLite 的核心功能。理解了這些的開發者在使用 SQLite 時就會很容易了。

注意上面列出的這些介面只是一類介面而不是實際的介面。這些介面都有許多不同的版本。比如,上面列出的一個叫做 sqlite3_open() 的介面,事實上是由 3 個完全不同的介面組成的:sqlite3_open()sqlite3_open16() 還有 sqlite3_open_v2()。上面列表中提到的sqlite3_column() 實際上並不存在。列表中提到的 “sqlite3_column()” 實際上是由一簇為了獲取不同列型別的介面組成。

下面是核心介面的簡要介紹:

sqlite3_open()    這個介面開啟一個到 SQLite 資料庫檔案的連結並返回一個資料庫連線物件。這通常是應用程式呼叫的第一個 SQLite 的 API,並且也是其他大部分的 SQLite API 所需要的。大部分的 SQLite 介面需要一個指向 database connection object 的指標作為第一個引數,可以認為是資料庫連線物件上的方法。這個介面是資料庫連線物件的構造器。

sqlite3_prepare()    這個介面將 SQL 語句轉換為一個 prepared statement 物件並返回指向這個物件的指標。這個介面需要之前使用 sqlite3_open() 返回的資料庫連線物件,還有一個包含 SQL 語句的文字字串作為引數。這個 API 實際上並不執行 SQL 語句。它僅僅只是準備用於執行的 SQL 語句。把每個 SQL 語句想象成一個小型的計算機程式。sqlite3_prepare() 是為了把那個程式編譯成物件程式碼(object code)。Prepared statement 就是這個物件程式碼。之後 sqlite3_step() 執行這個物件程式碼獲取結果。

注意對於新的程式已經不推薦使用 sqlite3_prepare()。新的應用推薦使用sqlite3_prepare_v2() 介面。

sqlite3_step()     這個介面用於執行之前用 sqlite3_prepare() 建立的 prepared statement。這個介面只返回結果集的第一條結果。為了獲取第二條結果,再呼叫一次sqlite3_step()。繼續呼叫 sqlite3_step() 直到語句結束。不返回結果的語句(比如:INSERT, UPDATE, 或者 DELETE 語句)呼叫一次 sqlite3_step() 就行了。

sqlite3_column()    這個介面返回使用 sqlite3_step() 查詢的 prepared statement 的結果集中當前行的某一列。每次呼叫完 sqlite3_step() 都會產生一個新的 result set row。這個介面可以被呼叫多次用於獲取一行中的不同列。正如上面所提到的,事實上在 SQLite 的 API 中並沒有 “sqlite3_column()” 這個函式。相反的,我們這裡呼叫的 “sqlite3_column()” 是為了獲取某列中不同型別值的一簇的介面占位符(a place-holder for an entire family of functions)。這類介面中有返回結果大小(如果是字串或者 BLOB,譯註:Binary Large OBject)還有結果集中列數的介面。

sqlite3_column_blob()  
sqlite3_column_bytes()  
sqlite3_column_bytes16()  
sqlite3_column_count()  
sqlite3_column_double()  
sqlite3_column_int()  
sqlite3_column_int64()  
sqlite3_column_text()  
sqlite3_column_text16()  
sqlite3_column_type()  
sqlite3_column_value()

sqlite3_finalize()    這個介面銷燬之前由 sqlite3_prepare() 建立的 prepared statement。為了避免記憶體洩露,必須這個介面銷燬之前建立的 prepared statement。

sqlite3_close()    這個介面關閉之前由呼叫 sqlite3_open() 建立的資料庫連線。在關閉資料庫連線前所有與之關聯的 prepared statements 都應該已經被銷燬了。

1.1 核心介面和物件的使用方法

一個想要使用 SQLite 的應用程式通常在初始化時使用 sqlite3_open() 建立一個資料庫連線。注意 sqlite3_open() 既可以用於開啟一個現存的資料庫,也可以建立並開啟一個新的資料庫。因為許多的應用程式只使用一個資料庫連線,所以就沒有理由讓一個應用程式多次呼叫sqlite3_open() 建立多個資料庫連線 – 同一個資料庫或者不同的資料庫。有時一個多執行緒的應用會為不同的執行緒建立獨立的資料庫連線。注意,為了訪問兩個或者多個資料庫也沒必要建立多個獨立的連線。一個單一的資料庫連線可以使用 ATTACH SQL 語句同時訪問兩個或者多個資料庫(譯註:http://sqlite.awardspace.info/syntax/sqlitepg12.htm)。

許多應用在關閉時呼叫 sqlite3_close() 銷燬它們的資料庫連線。比如,一個使用 SQLite 作為它的應用程式檔案格式(application file format)會在點選 檔案/開啟(File/Open) 選單時建立一個資料庫連線,在點選 檔案/關閉 (File/Close) 選單時關閉這個連線。

要執行 SQL 語句,程式需要遵循以下幾步:

使用 **sqlite3_prepare()** 建立一個 prepared statement。      
通過一次或多次呼叫 **sqlite3_step()** 查詢 prepared statement 的結果。    
對於查詢來說,在呼叫 **sqlite3_step()** 後通過呼叫 **sqlite3_column()** 獲取結果。    
使用 **sqlite3_finalize()** 銷燬 prepared statement。

上述都是為了高效的使用 SQLite 讀者所需要知道的。其餘的都只是補充和細節。

2.0 核心 API 的便捷封裝

sqlite3_exec() 是使用一次函式呼叫完成上述四種介面呼叫的便捷封裝。 sqlite3_exec()在處理結果集的每行時呼叫傳入的回撥函式。sqlite3_get_table() 是另一個使用一次函式呼叫完成上述四種介面呼叫的便捷封裝。sqlite3_get_table() 與 sqlite3_exec() 的不同之處是將結果集儲存在堆中而不是每次都呼叫回撥函式。

需要注意的是 sqlite3_exec() 和 sqlite3_get_table() 都不能實現核心介面不能完成的事。事實上,這些封裝都是完全由核心介面實現的。

3.0 引數繫結與重用 Prepared Statements

在之前的討論中,都假設每個 SQL 語句都只准備一次( prepared once),執行(evaluated),然後銷燬。但是,SQLite 允許相同的 prepared statement 被執行多次。通過以下的方法實現:

sqlite3_reset()
sqlite3_bind()

sqlite3_step() 執行一次或多次 prepared statement 後,通過 sqlite3_reset() 可以重置並重新執行(evaluated)。對現存的 prepared statement 使用 sqlite3_reset() 可以避免呼叫 sqlite3_prepare() 建立一個新的 prepared statement。對於部分的 SQL 語句,呼叫sqlite3_prepare() 的時間和呼叫 sqlite3_step() 一樣。所以避免呼叫sqlite3_prepare() 對效能提升有重大的影響。

通常不會對一個 SQL 語句執行(evaluate)多次。更常見的是,執行一個相似的語句。例如,你想通過執行多次 INSERT 語句插入不同的值。為了實現類似的靈活性,SQLite 允許對一條 SQL 語句每次“繫結”不同的值。這些值之後可以改變,並且同樣的 prepared statement 使用新的值可以二次使用。(譯註:說白了就是對一個表一次插入多條資料,每次插入的不同的值在 SQL 語句中用萬用字元佔位)

在 SQLite 中,任何地方都允許插入字串字面量(string literal),可以使用以下幾種形式:

?
?NNN
:AAA
$AAA
@AAA

在上面個的例子中,NNN 代表整型值( integer value ),AAA 是個識別符號(identifier)(譯註:字母數字組合)。引數的初始值為 NULL。在第一次呼叫 sqlite3_step() 之前或立即在呼叫 sqlite3_reset() 之後,應用程式可以呼叫某個 sqlite3_bind() 介面繫結值到引數上。每次呼叫 sqlite3_bind() 都會覆蓋之前繫結到相同引數的值。

應用可以按需要提前準備多個 SQL prepared statements 並按需要執行(evaluate)。沒有嚴格的限制 prepared statements 的數量。

4.0 配置 SQLite

預設的 SQLite 配置對於大部分的應用工作的都挺好的。但有時開發者想要優化設定項去嘗試壓榨出更多的效能,或者利用一些隱蔽的特性。

sqlite3_config() 可以設定 SQLite 全域性的,程式級(process-wide)的配置項。sqlite3_config() 只能在資料庫連線建立後被呼叫。sqlite3_config() 允許程式設計師做以下的事情:

調整 SQLite 如何分配記憶體,包括為安全敏感(safety-critical)的實時的嵌入式系統和應用程式定義的(application-defined)記憶體分配器設定為可選的(alternative)記憶體分配器(memory allocators)。
設定一個程式級的錯誤日誌。
指定一個應用程式定義的頁快取(page cache)。
調整 mutex 的使用,這樣就可以使用多種執行緒模型,或者替換一個程式定義的 mutex 系統。

在程式級的設定完成(configuration is complete)並且資料庫連線已經建立後,不同的資料庫連線可以通過呼叫 sqlite3_limit() 和 sqlite3_db_config() 配置。

5.0 擴充套件 SQLite

SQLite 包含可以擴充套件功能的介面。這些介面(routine)包括:

sqlite3_create_collation()  
sqlite3_create_function()  
sqlite3_create_module()  
sqlite3_vfs_register()

sqlite3_create_collation() 介面用於建立排序文字用的新的校對佇列(collating sequences)。sqlite3_create_module() 介面用於註冊新的虛表實現。sqlite3_vfs_register() 建立一個新的 VFS(譯註:Virtual File System,虛擬檔案系統)。

sqlite3_create_function() 介面用於建立新的 SQL 函式(function)—— scalar 函式或者 aggregate 函式(譯註:http://www.w3schools.com/sql/sql_functions.asp)。新的函式實現通常使用以下的額外介面:

sqlite3_aggregate_context()
sqlite3_result()
sqlite3_user_data()
sqlite3_value()

所有的 SQLite 內建 SQL 函式都使用的是這些介面建立的。可以參考 SQLite 的原始檔,尤其是 date.c 和 func.c。

共享庫或者 DLL 可以作為 SQLite 的可裝卸擴充套件(loadable extensions)(譯註:http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions)。

6.0 其他介面

這篇文章只提到了 SQLite 的一些基礎介面。SQLite 庫中還包含一些這裡沒有提到的有用的 API。可以在 SQLite 的 C/C++ 的介面說明中找到完整的函式列表(譯註:http://sqlite.org/c3ref/intro.html)。參考此文件可以找到完整和權威的關於 SQLite 介面的資訊。

相關文章