"swarmvtab" 虛擬表格允許使用者查詢大量表格(以下稱為「組成」表格),這些表格具有相似的結構但 rowid 值範圍不同,就好像它們是單一資料庫表格一樣。這些表格可以(而且通常會)位於不同的資料庫中。Swarmvtab 表格為唯讀。
組成表格不得宣告為 WITHOUT ROWID,且所有表格都必須具有相同的結構,但可以在其資料庫中使用不同的名稱。在此情況下,「相同的結構」表示
swarmvtab 表格具有與其每個組成表格相同的結構。
swarmvtab 虛擬表格的建立方式如下
CREATE VIRTUAL TABLE temp.<name> USING swarmvtab(<sql-statement>);
Swarmvtab 虛擬表格必須在 temp 架構中建立。嘗試在主資料庫或附加資料庫中建立 swarmvtab 會產生錯誤。
提供給 CREATE VIRTUAL TABLE 陳述式的 SQL 陳述式會在建立表格時執行。它必須傳回四或五個欄位。傳回的每一列都說明一個元件表格。前四個欄位會從頭到尾解釋為
最後一個欄位的解釋,如果存在,在此說明。
例如,假設 SQL 陳述式在執行時傳回下列資料
資料庫 URI | 表格名稱 | 最小 rowid | 最大 rowid |
---|---|---|---|
test.db1 | t1 | 0 | 10 |
test.db2 | t2 | 11 | 20 |
test.db3 | t1 | 21 | 30 |
test.db4 | t1 | 31 | 40 |
而使用者查詢 rowid 值為 25 的 swarmvtab 表格。swarmvtab 表格會開啟資料庫檔案「test.db3」並讀取資料以從表格「t1」傳回(因為 25 落在「test.db3」中分配給表格「t1」的 rowid 範圍內)。
Swarmvtab 僅有效率地處理 rowid(或其他 INTEGER PRIMARY KEY)欄位的範圍和等值約束。如果查詢不包含此類約束,則 swarmvtab 會透過依序開啟每個資料庫並線性掃描元件表格來尋找結果。這會產生正確的結果,但通常很慢。
SQL 陳述式傳回的列中不得有重疊的 rowid 範圍。如果有,則為錯誤。
swarmvtab 實作可以在任何時候開啟或關閉資料庫。預設情況下,它會嘗試將同時開啟的資料庫檔案數量限制在九個。這不是硬性限制,有可能建立一個會讓 swarmvtab 超過限制的場景。
swarmvtab 虛擬表格的程式碼位於 SQLite 原始程式碼樹的 ext/misc/unionvtab.c 檔案中。可以使用類似以下的指令,將它編譯成 SQLite 可載入的擴充功能
gcc -g -fPIC -shared unionvtab.c -o unionvtab.so
或者,可以將 unionvtab.c 檔案編譯到應用程式中。在這種情況下,應該呼叫以下函式,以向每個新的資料庫連線註冊擴充功能
int sqlite3_unionvtab_init(sqlite3 *db, void*, void*);
傳遞的第一個引數應該是註冊擴充功能的資料庫控制代碼。第二個和第三個引數都應該傳遞 0。
原始檔案和進入點命名為「unionvtab」,而不是「swarmvtab」。Unionvtab 是與 swarmvtab 捆綁在一起的 單獨記錄 的虛擬表格。
大多數 swarmvtab 使用者只會使用上述功能。本節說明專門設計給更深奧使用案例的功能。這些功能都涉及在 CREATE VIRTUAL TABLE 指令中,將額外的選用參數指定在 SQL 陳述式之後。選用參數使用其名稱指定,後接一個「=」字元,再後接一個選用引號包住的值。空白可以分隔名稱、「=」字元和值。例如
CREATE VIRTUAL TABLE temp.sv USING swarmvtab ( 'SELECT ...', -- the SELECT statement maxopen = 20, -- An optional parameter missing='missing_udf' -- Another optional parameter );
以下各節說明支援的參數。指定一個無法辨識的參數名稱會產生錯誤。
如果參數名稱以冒號「:」開頭,則假設它是在執行 SQL 陳述式之前,要繫結到 SQL 陳述式的一個值。值總是繫結為文字。如果指定的 SQL 參數不存在,則會產生錯誤。例如
CREATE VIRTUAL TABLE temp.x1 USING swarmvtab ( "SELECT :dir || local_filename, tbl, min, max FROM components", :dir = '/home/user/app/databases/' );
當執行上述 CREATE VIRTUAL TABLE 陳述式時,swarmvtab 會將文字值「/home/user/app/databases/」繫結到 SQL 陳述式的 :dir 參數,然後再執行它。
單一 CREATE VIRTUAL TABLE 陳述式可能包含任意數量的 SQL 參數。
預設情況下,swarmvtab 會嘗試將同時開啟的資料庫數量限制為九個。此參數允許變更該限制。例如,若要建立一個 swarmvtab 資料表,該資料表最多可以同時開啟 30 個資料庫
CREATE VIRTUAL TABLE temp.x1 USING swarmvtab ( "SELECT ...", maxopen=30 );
在某些情況下,增加開啟的資料庫數量可能會提升效能。
「openclose」參數允許使用者指定一個 應用程式定義的 SQL 函式 的名稱,該函式將在 swarmvtab 開啟資料庫之前立即呼叫,並在關閉資料庫後再次呼叫。傳遞給開啟關閉函式的第一個引數是識別要開啟或剛才關閉的資料庫的檔案名稱或 URI(與提供給 CREATE VIRTUAL TABLE 命令的最左欄位中傳回的值相同)。第二個引數在函式在開啟資料庫之前呼叫時為整數值 0,在關閉資料庫後呼叫時為 1。例如,如果
CREATE VIRTUAL TABLE temp.x1 USING swarmvtab ( "SELECT ...", openclose = 'openclose_udf' );
那麼在開啟包含組件資料表的每個資料庫之前,swarmvtab 會有效執行
SELECT openclose_udf(<database-name>, 0);
在資料庫關閉後,swarmvtab 會執行等同於
SELECT openclose_udf(<database-name>, 1);
openclose 函式傳回的任何值都會被忽略。如果在開啟資料庫之前進行的呼叫傳回錯誤,則不會開啟資料庫檔案,並且錯誤會傳回給使用者。這是 swarmvtab 會發出「開啟」呼叫但不會發出對應「關閉」呼叫的唯一情況。如果仍有資料庫開啟,「關閉」呼叫可能會從應用程式資料庫上最終的 sqlite3_close() 呼叫中發出,該資料庫會刪除 swarmvtab 資料表所在的暫時架構。
「關閉」呼叫傳回的錯誤總是會被忽略。
「missing」參數允許使用者指定 應用程式定義的 SQL 函數 的名稱,當 swarmvtab 開啟資料庫時,如果發現所需的資料庫檔案不在磁碟上,就會呼叫該函數。這讓應用程式有機會在 swarmvtab 嘗試開啟資料庫之前,從遠端來源擷取所需的資料庫。傳遞給「missing」函數的唯一參數是識別正在開啟的資料庫的名稱或 URI。假設
CREATE VIRTUAL TABLE temp.x1 USING swarmvtab ( "SELECT ...", openclose = 'openclose_udf', missing='missing_udf' );
接著 missing 函數會如下呼叫
SELECT missing_udf(<database-name>);
如果 missing 函數傳回錯誤,則不會開啟資料庫,並將錯誤傳回給使用者。如果已設定 openclose 函數,則會在此時發出「close」呼叫,以符合先前的「open」。以下偽程式碼說明了在設定 missing 和 openclose 函數的 swarmvtab 實例開啟組件資料庫時所使用的程序。
SELECT openclose_udf(<database-name>, 0); if( error ) return error; if( db does not exist ){ SELECT missing_udf(<database-name>); if( error ){ SELECT openclose_udf(<database-name>, 1); return error; } } sqlite3_open_v2(<database-name>); if( error ){ SELECT openclose_udf(<database-name>, 1); return error; } // db successfully opened!
如果 CREATE VIRTUAL TABLE 指令中指定為 SELECT 陳述式傳回五個欄位,則最後一個欄位僅用於應用程式內容。Swarmvtab 完全不使用這個值,除非它在指定時傳遞給 openclose 和 missing 函數,在 <database-name> 之後。換句話說,如果存在「context」欄位,swarmvtab 會呼叫以下函數,而不是如上所述呼叫函數
SELECT missing_udf(<database-name>, <context>); SELECT openclose_udf(<database-name>, <context>, 0); SELECT openclose_udf(<database-name>, <context>, 1);
視需要而定。
此頁面最後修改於 2022-01-08 05:02:57 UTC