小巧、快速、可靠。
任選三項。

編輯備註:此文件說明 SQLite 2 版,已於 2004 年停用並由 SQLite3 取代。此文件保留為 SQLite 的歷史記錄的一部分。現代程式設計人員應參閱本網站其他地方提供的最新 SQLite 文件。

SQLite 2 版的 C 語言介面

SQLite 函式庫的設計非常易於從 C 或 C++ 程式使用。此文件概述 C/C++ 程式設計介面。

1.0 核心 API

SQLite 函式庫的介面包含三個核心函式、一個不透明資料結構和一些用作回傳值的常數。核心介面如下

typedef struct sqlite sqlite;
#define SQLITE_OK           0   /* Successful result */

sqlite *sqlite_open(const char *dbname, int mode, char **errmsg);

void sqlite_close(sqlite *db);

int sqlite_exec(
  sqlite *db,
  char *sql,
  int (*xCallback)(void*,int,char**,char**),
  void *pArg,
  char **errmsg
);

以上是您在 C 或 C++ 程式中使用 SQLite 所真正需要知道的一切。還有其他介面函式可用(並在下方說明),但我們將從說明上面顯示的核心函式開始。

1.1 開啟資料庫

使用 sqlite_open 函式開啟現有的 SQLite 資料庫或建立新的 SQLite 資料庫。第一個參數是資料庫名稱。第二個參數用於表示資料庫是用於讀寫還是僅用於讀取。但在目前的實作中,會忽略 sqlite_open 的第二個參數。第三個參數是指向字串指標的指標。如果第三個參數不為 NULL 且在嘗試開啟資料庫時發生錯誤,則會將錯誤訊息寫入從 malloc() 取得的記憶體,並讓 *errmsg 指向此錯誤訊息。呼叫函式負責在完成後釋放記憶體。

SQLite 資料庫的名稱是包含資料庫的檔案名稱。如果檔案不存在,SQLite 會嘗試建立並初始化它。如果檔案是唯讀的(因為權限位元或因為它位於唯讀媒體,例如 CD-ROM),SQLite 會開啟資料庫以進行唯讀。整個 SQL 資料庫儲存在磁碟上的單一檔案中。但是,在執行 SQL 命令期間可能會建立其他暫時檔案,以儲存資料庫回滾日誌或查詢的暫時和中間結果。

sqlite_open 函式的傳回值是指向不透明 sqlite 結構的指標。此指標將是所有後續處理相同資料庫的 SQLite 函式呼叫的第一個引數。如果開啟因任何原因失敗,則傳回 NULL。

1.2 關閉資料庫

若要關閉 SQLite 資料庫,請呼叫 sqlite_close 函式,並傳遞從先前呼叫 sqlite_open 取得的 sqlite 結構指標。如果資料庫關閉時交易處於活動狀態,則交易會回滾。

1.3 執行 SQL 陳述式

sqlite_exec 函式用於處理 SQL 陳述式和查詢。此函式需要 5 個參數,如下所示

  1. 從先前呼叫 sqlite_open 取得的 sqlite 結構的指標。

  2. 包含一個或多個要處理的 SQL 陳述式和/或查詢的以零終止的字串。

  3. 指向回呼函式的指標,該指標會針對查詢結果中的每一列呼叫一次。此引數可以是 NULL,在這種情況下,永遠不會呼叫任何回呼。

  4. 一個指標,傳遞給回呼函數作為第一個參數。

  5. 一個指向錯誤字串的指標。錯誤訊息會寫入從 malloc() 取得的空間,而錯誤字串會指向該已配置空間。呼叫函數負責在完成後釋放此空間。此參數可以是 NULL,在這種情況下,錯誤訊息不會回報給呼叫函數。

回呼函數用於接收查詢結果。回呼函數的原型如下

int Callback(void *pArg, int argc, char **argv, char **columnNames){
  return 0;
}

傳遞給回呼函數的第一個參數只是 sqlite_exec 第四個參數的副本。此參數可用於從用戶端程式碼傳遞任意資訊給回呼函數。第二個參數是查詢結果中的欄位數。第三個參數是一個指標陣列,指向字串,其中每個字串都是該記錄的單一欄位。請注意,回呼函數會將資料庫中的 NULL 值回報為 NULL 指標,這與空字串非常不同。如果第 i 個參數是空字串,我們會得到

argv[i][0] == 0

但如果第 i 個參數是 NULL,我們會得到

argv[i] == 0

欄位名稱包含在第四個參數的前 argc 個項目中。如果 SHOW_DATATYPES pragma 已開啟(預設為關閉),則第四個參數中的第二個 argc 個項目是對應欄位的資料類型。

如果 EMPTY_RESULT_CALLBACKS pragma 已設定為 ON,且查詢結果為空集合,則回呼函數會呼叫一次,第三個參數 (argv) 設定為 0。換句話說

argv == 0
第二個參數 (argc) 和第四個參數 (columnNames) 仍然有效,且可用於在有結果時,判斷結果欄位的名稱和數量。如果結果集為空,預設行為是不呼叫 callback。

callback 函式通常應傳回 0。如果 callback 函式傳回非 0,查詢會立即中止,且 sqlite_exec 會傳回 SQLITE_ABORT。

1.4 錯誤碼

sqlite_exec 函式通常會傳回 SQLITE_OK。但如果發生問題,它可能會傳回不同的值來指出錯誤類型。以下是傳回碼的完整清單

#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 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_ROW         100  /* sqlite_step() has another row ready */
#define SQLITE_DONE        101  /* sqlite_step() has finished executing */

這些傳回值的意義如下

SQLITE_OK

如果一切正常且沒有錯誤,會傳回此值。

SQLITE_INTERNAL

此值表示 SQLite 函式庫內部的相容性檢查失敗。這只有在 SQLite 函式庫有錯誤時才會發生。如果您從 sqlite_exec 呼叫中收到 SQLITE_INTERNAL 回應,請在 SQLite 郵寄清單上回報問題。

SQLITE_ERROR

此傳回值表示傳入 sqlite_exec 的 SQL 中有錯誤。

SQLITE_PERM

此傳回值表示資料庫檔案的存取權限,導致檔案無法開啟。

SQLITE_ABORT

如果 callback 函式傳回非 0,會傳回此值。

SQLITE_BUSY

此傳回碼表示另一個程式或執行緒已鎖定資料庫。SQLite 允許兩個或更多執行緒同時讀取資料庫,但同時只能有一個執行緒開啟資料庫進行寫入。SQLite 中的鎖定是針對整個資料庫。

SQLITE_LOCKED

此回傳碼類似於 SQLITE_BUSY,表示資料庫已鎖定。但鎖定的來源是對sqlite_exec的遞迴呼叫。只有當您嘗試從先前呼叫 sqlite_exec 的查詢的回呼常式中呼叫 sqlite_exec 時,才會發生此回傳。只要不嘗試寫入相同的表格,就可以允許對 sqlite_exec 進行遞迴呼叫。

SQLITE_NOMEM

如果對malloc的呼叫失敗,則會傳回此值。

SQLITE_READONLY

此回傳碼表示嘗試寫入僅供讀取開啟的資料庫檔案。

SQLITE_INTERRUPT

如果對sqlite_interrupt的呼叫中斷正在進行的資料庫操作,則會傳回此值。

SQLITE_IOERR

如果作業系統通知 SQLite 它無法執行某些磁碟 I/O 操作,則會傳回此值。這表示磁碟上可能沒有更多空間。

SQLITE_CORRUPT

如果 SQLite 偵測到它正在處理的資料庫已損毀,則會傳回此值。損毀可能是由於流氓程序寫入資料庫檔案,或可能是由於 SQLite 中先前未偵測到的邏輯錯誤。如果磁碟 I/O 錯誤以使 SQLite 被迫將資料庫檔案留在損毀狀態的方式發生,也會傳回此值。後者應僅因硬體或作業系統故障而發生。

SQLITE_FULL

如果插入失敗是因為磁碟上沒有更多空間,或資料庫太大而無法再容納更多資訊,則會傳回此值。後一種情況應僅發生在大小超過 2GB 的資料庫。

SQLITE_CANTOPEN

如果因為某些原因無法開啟資料庫檔案,會傳回此值。

SQLITE_PROTOCOL

如果其他程序正在處理檔案鎖定,並違反 SQLite 在其回滾日誌檔案中使用的檔案鎖定協定,會傳回此值。

SQLITE_SCHEMA

當資料庫首次開啟時,SQLite 會將資料庫結構讀取至記憶體,並使用該結構來分析新的 SQL 陳述式。如果其他程序變更結構,目前正在處理的命令會中止,因為所產生的虛擬機器碼假設舊結構。這是此類案例的傳回碼。通常重新執行命令會清除問題。

SQLITE_TOOBIG

SQLite 不會在單一資料表的單一列中儲存超過約 1 MB 的資料。如果您嘗試在單一列中儲存超過 1 MB 的資料,您會取得此傳回碼。

SQLITE_CONSTRAINT

如果 SQL 陳述式會違反資料庫約束,會傳回此常數。

SQLITE_MISMATCH

當嘗試將非整數資料插入標示為 INTEGER PRIMARY KEY 的欄位時,會發生此錯誤。對於大多數欄位,SQLite 會忽略資料類型,並允許儲存任何類型的資料。但是,INTEGER PRIMARY KEY 欄位只允許儲存整數資料。

SQLITE_MISUSE

如果錯誤使用一個或多個 SQLite API 常式,可能會發生此錯誤。錯誤使用的範例包括在使用 sqlite_close 關閉資料庫後呼叫 sqlite_exec,或從兩個不同的執行緒同時使用相同的資料庫指標呼叫 sqlite_exec

SQLITE_NOLFS

這個錯誤表示您嘗試在缺乏大型檔案支援的舊式 Unix 機器上建立或存取大於 2GB 的檔案資料庫檔案。

SQLITE_AUTH

此錯誤表示授權回呼已禁止您嘗試執行的 SQL。

SQLITE_ROW

這是 sqlite_step 常式程式(非回呼 API 的一部分)的其中一個回傳碼。它表示有另一列結果資料可用。

SQLITE_DONE

這是 sqlite_step 常式程式(非回呼 API 的一部分)的其中一個回傳碼。它表示 SQL 陳述式已完全執行,且 sqlite_finalize 常式程式已準備好呼叫。

2.0 不使用回呼函數存取資料

上面說明的 sqlite_exec 常式程式過去是從 SQLite 資料庫擷取資料的唯一方法。但是許多程式設計師發現使用回呼函數取得結果並不方便。因此從 SQLite 版本 2.7.7 開始,提供了一個不使用回呼的第二個存取介面。

新介面使用三個獨立的函數來取代單一的 sqlite_exec 函數。

typedef struct sqlite_vm sqlite_vm;

int sqlite_compile(
  sqlite *db,              /* The open database */
  const char *zSql,        /* SQL statement to be compiled */
  const char **pzTail,     /* OUT: uncompiled tail of zSql */
  sqlite_vm **ppVm,        /* OUT: the virtual machine to execute zSql */
  char **pzErrmsg          /* OUT: Error message. */
);

int sqlite_step(
  sqlite_vm *pVm,          /* The virtual machine to execute */
  int *pN,                 /* OUT: Number of columns in result */
  const char ***pazValue,  /* OUT: Column data */
  const char ***pazColName /* OUT: Column names and datatypes */
);

int sqlite_finalize(
  sqlite_vm *pVm,          /* The virtual machine to be finalized */
  char **pzErrMsg          /* OUT: Error message */
);

策略是使用 sqlite_compile 編譯單一 SQL 陳述式,然後多次呼叫 sqlite_step(每次呼叫對應一列輸出),最後呼叫 sqlite_finalize 來清除 SQL 執行完畢後的資料。

2.1 將 SQL 陳述式編譯成虛擬機器

sqlite_compile 會「編譯」單一 SQL 陳述式(由第二個參數指定),並產生一個能夠執行該陳述式的虛擬機器。與大多數介面常式程式一樣,第一個參數必須是指向從先前呼叫 sqlite_open 取得的 sqlite 結構的指標。

虛擬機器指標儲存在作為第 4 個參數傳入的指標中。用於存放虛擬機器的空間會動態配置。為了避免記憶體外洩,呼叫函數必須在完成使用虛擬機器後對其呼叫 sqlite_finalize。如果在編譯期間遇到錯誤,第 4 個參數可以設定為 NULL。

如果在編譯期間遇到任何錯誤,錯誤訊息會寫入從 malloc 取得的記憶體中,而第 5 個參數會指向該記憶體。如果第 5 個參數為 NULL,則不會產生錯誤訊息。如果第 5 個參數不為 NULL,則呼叫函數應透過呼叫 sqlite_freemem 來處理包含錯誤訊息的記憶體。

如果第 2 個參數實際上包含兩個或多個 SQL 陳述式,則只會編譯第一個陳述式。(這與 sqlite_exec 的行為不同,後者會執行其輸入字串中的所有 SQL 陳述式。)sqlite_compile 的第 3 個參數會指向輸入中第一個 SQL 陳述式結尾後的字元。如果第 2 個參數只包含單一 SQL 陳述式,則第 3 個參數會指向第 2 個參數結尾的 '\000' 終止符。

成功時,sqlite_compile 會傳回 SQLITE_OK。否則會傳回錯誤碼。

2.2 SQL 陳述式的逐步執行

使用 sqlite_compile 產生虛擬機器後,會透過一次或多次呼叫 sqlite_step 來執行它。除了最後一次呼叫外,每次呼叫 sqlite_step 都會傳回結果的一列。結果中的欄位數目儲存在第 2 個參數所指向的整數中。第 3 個參數所指定的指標會指向欄位值的指標陣列。第 4 個參數中的指標會指向欄位名稱和資料類型的指標陣列。sqlite_step 的第 2 至第 4 個參數傳達的資訊與使用 sqlite_exec 介面時,callback 常式的第 2 至第 4 個參數相同。但使用 sqlite_step 時,無論 SHOW_DATATYPES pragma 是否開啟,欄位資料類型資訊總是包含在第 4 個參數中。

每次呼叫 sqlite_step 會傳回一個整數代碼,表示該步驟中發生了什麼事。此代碼可能是 SQLITE_BUSY、SQLITE_ROW、SQLITE_DONE、SQLITE_ERROR 或 SQLITE_MISUSE。

如果虛擬機器無法開啟資料庫檔案,因為它被另一個執行緒或程序鎖定,sqlite_step 會傳回 SQLITE_BUSY。呼叫函數應該執行其他活動,或暫停一小段時間,讓鎖定有機會清除,然後再次呼叫 sqlite_step。可以重複此動作任意次數。

每當有另一列結果資料可用時,sqlite_step 會傳回 SQLITE_ROW。列資料儲存在指向字串的指標陣列中,而第二個參數會指向這個陣列。

當所有處理完成時,sqlite_step 會傳回 SQLITE_DONE 或 SQLITE_ERROR。SQLITE_DONE 表示陳述式已順利完成,而 SQLITE_ERROR 表示發生執行時期錯誤。(錯誤的詳細資料可從 sqlite_finalize 取得。)在 sqlite_step 傳回 SQLITE_DONE 或 SQLITE_ERROR 之後,再次呼叫 sqlite_step 是對函式庫的誤用。

sqlite_step 傳回 SQLITE_DONE 或 SQLITE_ERROR 時,*pN 和 *pazColName 值會設定為結果集中的欄位數目和欄位名稱,就像 SQLITE_ROW 回傳一樣。這讓呼叫程式碼可以找出結果欄位數目、欄位名稱和資料類型,即使結果集是空的。當回傳代碼是 SQLITE_DONE 或 SQLITE_ERROR 時,*pazValue 參數會永遠設定為 NULL。如果執行的 SQL 是不傳回結果的陳述式(例如 INSERT 或 UPDATE),則 *pN 會設定為零,而 *pazColName 會設定為 NULL。

如果您濫用函式庫,嘗試不當呼叫sqlite_step,它會嘗試傳回 SQLITE_MISUSE。這可能會發生在您從兩個或多個執行緒同時在同一虛擬機器上呼叫 sqlite_step(),或是在它傳回 SQLITE_DONE 或 SQLITE_ERROR 後再次呼叫 sqlite_step(),或是在傳遞無效的虛擬機器指標給 sqlite_step() 時。您不應依賴 SQLITE_MISUSE 傳回碼來指出錯誤。介面濫用有可能會未被偵測到,並導致程式崩潰。SQLITE_MISUSE 僅用於除錯輔助,以協助您在發生意外之前偵測到不正確的使用方式。濫用偵測邏輯無法保證在每個案例中都能運作。

2.3 刪除虛擬機器

sqlite_compile 建立的每個虛擬機器最終都應該傳遞給 sqlite_finalize。sqlite_finalize() 程序會釋放虛擬機器使用的記憶體和其他資源。未呼叫 sqlite_finalize() 會導致您的程式出現資源外洩。

sqlite_finalize 常式也會傳回結果碼,指出虛擬機器執行的 SQL 作業是否成功或失敗。sqlite_finalize() 傳回的值會與使用 sqlite_exec 執行相同 SQL 時傳回的值相同。傳回的錯誤訊息也會相同。

sqlite_step 傳回 SQLITE_DONE 之前,呼叫虛擬機器上的 sqlite_finalize 是可以接受的。這樣做會中斷正在進行的作業。部分完成的變更會被還原,而且資料庫會回復到其原始狀態(除非使用正在執行的 SQL 中的 ON CONFLICT 子句選取替代的復原演算法)。效果與 sqlite_exec 的回呼函式傳回非零值相同。

在從未傳遞給 sqlite_step 的虛擬機器上呼叫 sqlite_finalize 也是可以接受的。

3.0 延伸 API

使用 SQLite 僅需要第 1.0 節中描述的三個核心例程。但還有許多其他函式提供有用的介面。這些延伸例程如下

int sqlite_last_insert_rowid(sqlite*);

int sqlite_changes(sqlite*);

int sqlite_get_table(
  sqlite*,
  char *sql,
  char ***result,
  int *nrow,
  int *ncolumn,
  char **errmsg
);

void sqlite_free_table(char**);

void sqlite_interrupt(sqlite*);

int sqlite_complete(const char *sql);

void sqlite_busy_handler(sqlite*, int (*)(void*,const char*,int), void*);

void sqlite_busy_timeout(sqlite*, int ms);

const char sqlite_version[];

const char sqlite_encoding[];

int sqlite_exec_printf(
  sqlite*,
  char *sql,
  int (*)(void*,int,char**,char**),
  void*,
  char **errmsg,
  ...
);

int sqlite_exec_vprintf(
  sqlite*,
  char *sql,
  int (*)(void*,int,char**,char**),
  void*,
  char **errmsg,
  va_list
);

int sqlite_get_table_printf(
  sqlite*,
  char *sql,
  char ***result,
  int *nrow,
  int *ncolumn,
  char **errmsg,
  ...
);

int sqlite_get_table_vprintf(
  sqlite*,
  char *sql,
  char ***result,
  int *nrow,
  int *ncolumn,
  char **errmsg,
  va_list
);

char *sqlite_mprintf(const char *zFormat, ...);

char *sqlite_vmprintf(const char *zFormat, va_list);

void sqlite_freemem(char*);

void sqlite_progress_handler(sqlite*, int, int (*)(void*), void*);

上述所有定義都包含在原始碼樹中的「sqlite.h」標頭檔案中。

3.1 最近一次插入的 ROWID

SQLite 資料表的每一列都有唯一的整數鍵。如果資料表有一個標記為 INTEGER PRIMARY KEY 的欄位,則該欄位會作為鍵。如果沒有 INTEGER PRIMARY KEY 欄位,則鍵會是一個唯一的整數。可以使用「ROWID」、「OID」或「_ROWID_」等名稱在 SELECT 陳述式中存取一列的鍵,或在 WHERE 或 ORDER BY 子句中使用它。

當您對沒有 INTEGER PRIMARY KEY 欄位的資料表執行插入,或資料表有 INTEGER PRIMARY KEY 但插入的 VALUES 子句中未指定該欄位的值時,系統會自動產生鍵。您可以使用 sqlite_last_insert_rowid API 函式找出最近一次 INSERT 陳述式的鍵值。

3.2 已變更的列數

sqlite_changes API 函數會傳回自資料庫上一次靜止後已插入、刪除或修改的列數。一個「靜止」的資料庫是指沒有任何未完成的 sqlite_exec 呼叫,且沒有任何由 sqlite_compile 建立且尚未由 sqlite_finalize 完成的 VM。在一般使用中,sqlite_changes 會傳回由最近一次的 sqlite_exec 呼叫或自最近一次的 sqlite_compile 以來所插入、刪除或修改的列數。但如果您有巢狀的 sqlite_exec 呼叫(也就是說,一個 sqlite_exec 的回呼常式呼叫另一個 sqlite_exec),或是在另一個 VM 仍然存在時呼叫 sqlite_compile 來建立新的 VM,那麼 sqlite_changes 所傳回數字的意義會更複雜。所報告的數字包含任何稍後由 ROLLBACK 或 ABORT 復原的變更。但因為 DROP TABLE 而刪除的列不會計算在內。

SQLite 透過刪除表格然後重新建立它來實作「DELETE FROM table」命令(沒有 WHERE 子句)。這比個別刪除表格的元素快很多。但這也表示 sqlite_changes 所傳回的值會是零,不論表格中原本有多少元素。如果需要準確計算已刪除元素的數量,請改用「DELETE FROM table WHERE 1」。

3.3 查詢到從 malloc() 取得的記憶體

sqlite_get_table 函數是 sqlite_exec 的包裝函數,它會收集所有來自連續回呼的資訊,並將其寫入從 malloc() 取得的記憶體中。這是一個便利函數,可讓應用程式透過單一函數呼叫取得資料庫查詢的完整結果。

sqlite_get_table 的主要結果是一個指向字串的指標陣列。在這個陣列中,每個結果的每一欄都有個元素。NULL 結果會以 NULL 指標表示。除了常規資料外,陣列開頭還新增了一列,其中包含每個結果欄位的名稱。

舉例來說,請考慮以下查詢

SELECT employee_name, login, host FROM users WHERE login LIKE 'd%';

此查詢將傳回每個員工的姓名、登入和主機電腦名稱,而這些員工的登入名稱都以字母「d」開頭。如果將此查詢提交給 sqlite_get_table,結果可能會如下所示

nrow = 2
ncolumn = 3
result[0] = "employee_name"
result[1] = "login"
result[2] = "host"
result[3] = "dummy"
result[4] = "No such user"
result[5] = 0
result[6] = "D. Richard Hipp"
result[7] = "drh"
result[8] = "zadok"

請注意,「dummy」記錄的「host」值為 NULL,因此 result[] 陣列在該槽位包含一個 NULL 指標。

如果查詢的結果集為空,則預設情況下 sqlite_get_table 會將 nrow 設定為 0,並將其 result 參數設定為 NULL。但如果 EMPTY_RESULT_CALLBACKS pragma 為開啟狀態,則 result 參數僅會初始化為欄位的名稱。例如,請考慮這個結果集為空的查詢

SELECT employee_name, login, host FROM users WHERE employee_name IS NULL;

預設行為會產生以下結果

nrow = 0
ncolumn = 0
result = 0

但如果 EMPTY_RESULT_CALLBACKS pragma 為開啟狀態,則會傳回以下結果

nrow = 0
ncolumn = 3
result[0] = "employee_name"
result[1] = "login"
result[2] = "host"

用於儲存 sqlite_get_table 所傳回資訊的記憶體是從 malloc() 取得。但呼叫函數不應嘗試直接釋放此資訊。相反地,當不再需要此資料表時,將完整的資料表傳遞給 sqlite_free_table。使用 NULL 指標呼叫 sqlite_free_table 是安全的,例如在結果集為空時傳回。

sqlite_get_table 常式傳回與 sqlite_exec 相同的整數結果碼。

3.4 中斷 SQLite 作業

sqlite_interrupt 函數可從不同的執行緒或訊號處理常式呼叫,以在第一個機會時導致目前的資料庫作業結束。當發生這種情況時,啟動資料庫作業的 sqlite_exec 常式(或等效常式)將傳回 SQLITE_INTERRUPT。

3.5 測試完整的 SQL 陳述式

下一個 SQLite 介面常式是便利函數,用於測試字串是否形成完整的 SQL 陳述式。如果 sqlite_complete 函數在輸入為字串時傳回 true,則參數形成完整的 SQL 陳述式。無法保證該陳述式的語法正確,但我們至少知道陳述式是完整的。如果 sqlite_complete 傳回 false,則需要更多文字才能完成 SQL 陳述式。

對於 sqlite_complete 函數的目的,如果 SQL 陳述式以分號結尾,則表示已完成。

sqlite 命令列公用程式使用 sqlite_complete 函數來得知何時需要呼叫 sqlite_exec。在收到每一行輸入後,sqlite 會對其緩衝區中的所有輸入呼叫 sqlite_complete。如果 sqlite_complete 傳回 true,則會呼叫 sqlite_exec,且輸入緩衝區會重設。如果 sqlite_complete 傳回 false,則提示會變更為繼續提示,且會讀取另一行文字並新增至輸入緩衝區。

3.6 函式庫版本字串

SQLite 函式庫匯出名為 sqlite_version 的字串常數,其中包含函式庫的版本號碼。標頭檔包含巨集 SQLITE_VERSION,其中包含相同的資訊。如果需要,程式可以將 SQLITE_VERSION 巨集與 sqlite_version 字串常數進行比較,以驗證標頭檔和函式庫的版本號碼是否相符。

3.7 函式庫字元編碼

預設情況下,SQLite 假設所有資料都使用固定大小的 8 位元字元 (iso8859)。但是,如果您在組態指令碼中提供 --enable-utf8 選項,則函式庫會假設 UTF-8 變數大小的字元。這會影響 LIKE 和 GLOB 算子以及 LENGTH() 和 SUBSTR() 函數。靜態字串 sqlite_encoding 會設定為「UTF-8」或「iso8859」,以表示函式庫的編譯方式。此外,sqlite.h 標頭檔會定義 SQLITE_UTF8SQLITE_ISO8859 巨集中的一個,視情況而定。

請注意,SQLite 使用的字元編碼機制無法在執行階段變更。這僅是編譯階段的選項。sqlite_encoding 字元字串只會告訴您函式庫的編譯方式。

3.8 變更函式庫對鎖定檔案的回應

sqlite_busy_handler 程序可註冊忙碌回呼,並開啟 SQLite 資料庫。當 SQLite 嘗試存取已鎖定的資料庫時,會呼叫忙碌回呼。回呼通常會執行一些其他有用的工作,或可能暫停,以讓鎖定有機會清除。如果回呼傳回非零值,則 SQLite 會再次嘗試存取資料庫,且循環會重複。如果回呼傳回零值,則 SQLite 會中止目前的作業,並傳回 SQLITE_BUSY。

sqlite_busy_handler 的引數是從 sqlite_open 傳回的不透明結構、指向忙碌回呼函式的指標,以及將作為忙碌回呼函式第一個引數傳遞的通用指標。當 SQLite 呼叫忙碌回呼函式時,它會傳送三個引數給它:作為 sqlite_busy_handler 的第三個引數傳遞的通用指標、函式庫嘗試存取的資料庫表格或索引的名稱,以及函式庫嘗試存取資料庫表格或索引的次數。

對於我們希望忙碌回呼函式休眠的常見情況,SQLite 函式庫提供了一個方便的常式 sqlite_busy_timeoutsqlite_busy_timeout 的第一個引數是指向開啟的 SQLite 資料庫的指標,第二個引數是毫秒數。在執行 sqlite_busy_timeout 之後,SQLite 函式庫會等待鎖定清除至少在傳回 SQLITE_BUSY 之前指定的毫秒數。為逾時指定零毫秒會回復預設行為。

3.9 使用 _printf() 包裝函式

四個公用函式

實作與 sqlite_execsqlite_get_table 相同的查詢功能。但是,四個 _printf 常式並未將完整的 SQL 陳述式作為其第二個引數,而是採用 printf 格式的格式字串。要執行的 SQL 陳述式是由此格式字串和附加到函式呼叫結尾的任何其他引數所產生。

使用 SQLite printf 函式而非 sprintf 有兩個優點。首先,使用 SQLite printf 常式,永遠不會有像 sprintf 那樣溢位靜態緩衝區的危險。SQLite printf 常式會自動配置 (並稍後釋放)足夠的記憶體來儲存產生的 SQL 陳述式。

SQLite printf 常式比 sprintf 擁有的第二個優點是兩個新的格式化選項,專門設計用於支援 SQL 中的字串文字。在格式化字串中,%q 格式化選項的運作方式與 %s 非常類似,它會從引數清單中讀取一個以 Null 結束的字串,並將其插入結果中。但 %q 會透過在替換字串中的每個單引號 (') 字元建立兩個副本,來轉譯插入的字串。這會產生在字串文字中跳脫單引號字串結束意義的效果。%Q 格式化選項的運作方式類似;它會像 %q 一樣轉譯單引號,並額外將結果字串括在單引號中。如果 %Q 格式化選項的引數是 NULL 指標,結果字串會是沒有單引號的 NULL。

考慮一個範例。假設您嘗試將字串值插入資料庫表格中,而該字串值是從使用者輸入取得的。假設要插入的字串儲存在名為 zString 的變數中。用於執行插入的程式碼可能如下所示

sqlite_exec_printf(db,
  "INSERT INTO table1 VALUES('%s')",
  0, 0, 0, zString);

如果 zString 變數包含像「Hello」這樣的文字,則此陳述式會正常運作。但假設使用者輸入像「Hi y'all!」這樣的字串。產生的 SQL 陳述式如下所示

INSERT INTO table1 VALUES('Hi y'all')

由於「y'all」字詞中的撇號,這不是有效的 SQL。但如果使用 %q 格式化選項取代 %s,如下所示

sqlite_exec_printf(db,
  "INSERT INTO table1 VALUES('%q')",
  0, 0, 0, zString);

則產生的 SQL 會如下所示

INSERT INTO table1 VALUES('Hi y''all')

這裡的撇號已跳脫,而 SQL 陳述式格式正確。當根據可能包含單引號字元 (') 的資料動態產生 SQL 時,最好總是使用 SQLite printf 常式和 %q 格式化選項,而不是 sprintf

如果使用 %Q 格式化選項取代 %q,如下所示

sqlite_exec_printf(db,
  "INSERT INTO table1 VALUES(%Q)",
  0, 0, 0, zString);

則產生的 SQL 會如下所示

INSERT INTO table1 VALUES('Hi y''all')

如果 zString 變數的值為 NULL,則產生的 SQL 會如下所示

INSERT INTO table1 VALUES(NULL)

上述所有 _printf() 常式都建立在以下兩個函數上

char *sqlite_mprintf(const char *zFormat, ...);
char *sqlite_vmprintf(const char *zFormat, va_list);

sqlite_mprintf() 常式就像標準函式庫 sprintf(),但它會將結果寫入從 malloc() 取得的記憶體中,並傳回指向已配置記憶體的指標。sqlite_mprintf() 也了解上述所述的 %q 和 %Q 延伸。sqlite_vmprintf() 是同一常式的變數參數版本。這些常式傳回的字串指標應該透過傳遞給 sqlite_freemem() 來釋放。

3.10 在大型查詢期間執行背景工作

sqlite_progress_handler() 常式可用於向 SQLite 資料庫註冊一個回呼常式,以便在對 sqlite_exec()sqlite_step() 和各種包裝函數進行長時間呼叫期間定期呼叫它。

回呼每 N 個虛擬機器運算呼叫一次,其中 N 提供為 sqlite_progress_handler() 的第二個參數。sqlite_progress_handler() 的第三個和第四個參數是指向要呼叫的常式的指標,以及要作為其第一個參數傳遞的空指標。

執行每個虛擬機器運算所需的時間會根據許多因素而有所不同。1 GHz 電腦的典型值在每秒 50 萬到 300 萬之間,但可能會高出或低出許多,具體取決於查詢。因此,很難根據虛擬機器運算來排程背景運算。建議相對頻繁地排程回呼(例如每 1000 個指令),並使用外部計時器常式來判斷是否需要執行背景工作。

4.0 新增 SQL 函數

從 2.4.0 版本開始,SQLite 允許使用 C 程式碼實作的新函式來擴充 SQL 語言。使用下列介面

typedef struct sqlite_func sqlite_func;

int sqlite_create_function(
  sqlite *db,
  const char *zName,
  int nArg,
  void (*xFunc)(sqlite_func*,int,const char**),
  void *pUserData
);
int sqlite_create_aggregate(
  sqlite *db,
  const char *zName,
  int nArg,
  void (*xStep)(sqlite_func*,int,const char**),
  void (*xFinalize)(sqlite_func*),
  void *pUserData
);

char *sqlite_set_result_string(sqlite_func*,const char*,int);
void sqlite_set_result_int(sqlite_func*,int);
void sqlite_set_result_double(sqlite_func*,double);
void sqlite_set_result_error(sqlite_func*,const char*,int);

void *sqlite_user_data(sqlite_func*);
void *sqlite_aggregate_context(sqlite_func*, int nBytes);
int sqlite_aggregate_count(sqlite_func*);

sqlite_create_function() 介面用於建立常規函式,而 sqlite_create_aggregate() 則用於建立新的聚合函式。在兩種情況下,db 參數都是已開啟的 SQLite 資料庫,函式應註冊在該資料庫上,zName 是新函式的名稱,nArg 是參數數量,而 pUserData 是指標,會原封不動地傳遞給函式的 C 實作。兩個常式在成功時會傳回 0,如果有任何錯誤則會傳回非 0 值。

函式名稱的長度不得超過 255 個字元。任何嘗試建立名稱長度超過 255 個字元的函式都會導致錯誤。

對於常規函式,xFunc 回呼會在每次函式呼叫時呼叫一次。xFunc 的實作應呼叫其中一個 sqlite_set_result_... 介面來傳回其結果。sqlite_user_data() 常式可用於擷取在註冊函式時傳入的 pUserData 指標。

對於聚合函式,xStep 回呼會在結果中的每一列呼叫一次,然後在最後呼叫 xFinalize 來計算最終答案。xStep 常式可以使用 sqlite_aggregate_context() 介面來配置記憶體,該記憶體會是 SQL 函式的特定執行個體所獨有。在呼叫 xFinalize 之後,此記憶體會自動刪除。sqlite_aggregate_count() 常式可用於找出傳遞給聚合函式的資料列數。xFinalize 回呼應呼叫其中一個 sqlite_set_result_... 介面來設定聚合函式的最終結果。

SQLite 現在使用此介面來實作其所有內建函式。如需有關如何建立新的 SQL 函式的更多資訊和範例,請檢閱檔案 func.c 中的 SQLite 原始碼。

5.0 多執行緒與 SQLite

如果 SQLite 是以 THREADSAFE 預處理器巨集設定為 1 編譯,則同時從同一個程序的兩個或更多執行緒使用 SQLite 是安全的。但每個執行緒都應該有自己的 sqlite* 指標,由 sqlite_open 傳回。同時讓兩個或更多執行緒存取同一個 sqlite* 指標絕不安全。

在網站上提供的預編譯 SQLite 函式庫中,Unix 版本是在 THREADSAFE 關閉的狀態下編譯,但 Windows 版本是在 THREADSAFE 開啟的狀態下編譯。如果您需要不同的設定,則必須重新編譯。

在 Unix 中,sqlite* 指標不應透過 fork() 系統呼叫傳遞到子程序。子程序應在 fork() 之後開啟自己的資料庫副本。

6.0 使用範例

如需有關如何使用 SQLite C/C++ 介面的範例,請參閱原始碼樹的檔案 src/shell.c 中的 sqlite 程式。有關 sqlite 的更多資訊,請參閱 cli.html。另請參閱原始碼檔案 src/tclsqlite.c 中的 SQLite Tcl 介面原始碼。