冒牌表是附加到與索引相同的 B 樹 的表。冒牌表允許查詢或修改索引的內容,就好像索引是普通表一樣。
冒牌表僅用於分析和偵錯。這不是大多數應用程式開發人員應該了解或甚至知道的特性。冒牌表僅供專家使用。
不當使用冒牌表可能會導致索引損毀,不過,透過執行 REINDEX,可以修復由此產生的任何損毀。
SQLite 中的每個表和每個索引都儲存在資料庫檔案中的一個獨立 B 樹中。每個 B 樹都由其根頁數識別。任何索引或表的根頁數都可以透過查詢 sqlite_schema 表 的「rootpage」欄位來找到。請參閱 索引教學 和 檔案格式 文件,以進一步了解此設計的背景。
通常,表和索引的 B 樹略有不同。表 B 樹包含 64 位元整數鍵和任意資料。64 位元整數鍵是 ROWID。索引 B 樹包含任意二進位鍵,但不包含資料。因此,表 B 樹和索引 B 樹並不直接相容。
不過,WITHOUT ROWID 表的 B 樹與索引 B 樹的格式相同。因此,可以存取索引 B 樹,就好像它是 WITHOUT ROWID 表一樣。
建立冒充表的其中一種方法是直接編輯 sqlite_schema 表格,以插入描述該表格的新列。例如,假設架構如下
CREATE TABLE t1(a INTEGER PRIMARY KEY,b TEXT,c INT, d INT); CREATE INDEX t1bc ON t1(b,c);
與 t1bc 索引具有相同結構的 WITHOUT ROWID 表格如下所示
CREATE TABLE t2(b TEXT,c INT,a INT, PRIMARY KEY(b,c,a)) WITHOUT ROWID;
若要針對索引「t1bc」建立永久冒充表「t2」,應先透過執行「PRAGMA writable_schema=ON」來啟用 sqlite_schema 表格的編輯。(請務必注意此 PRAGMA 附帶的警告。錯誤可能會導致資料庫嚴重損毀。)然後在 sqlite_schema 表格中插入新項目,如下所示
INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql) SELECT 'table','t2','t2',rootpage, 'CREATE TABLE t2(b,c,a,PRIMARY KEY(b,c,a))WITHOUT ROWID' FROM sqlite_schema WHERE name='t1bc';
上述 INSERT 陳述式會在 sqlite_schema 表格中新增一個新列,定義一個表格「t2」,其磁碟格式與索引「t1bc」相同,並指向相同的 b 樹。在新增此 sqlite_schema 表格項目後,必須關閉並重新開啟資料庫,才能讓 SQLite 重新讀取架構。然後可以查詢「t2」表格,以查看「t1bc」索引的內容。
上述手動冒充表方法的一個嚴重問題是,在將新「t2」項目新增至「sqlite_schema」表格後,資料庫檔案在技術上會損毀。「t1bc」索引和「t2」表格都會指向相同的 b 樹。雖然這不會造成任何立即的問題,但應避免執行 VACUUM。
可以寫入「t2」表格,從而變更索引的內容。但這樣做會讓「t1bc」索引與其父表格「t1」不同步。不同步的索引可能會導致查詢結果不正確。
由於「t2」冒充表是一種資料庫損毀,因此不建議手動建立冒充表。實際上,除了專家開發人員之外,不鼓勵任何人使用冒充表,但特別不鼓勵手動建立冒充表,因為它們是永久性的。
建立冒充表的另一種(較安全的)方法,是在不更新磁碟上的「sqlite_schema」表的狀況下,將冒充表的項目加入 SQLite 的內部符號表。這樣一來,冒充表只會存在於單一資料庫連線中,而且只要重新載入架構,就會自動移除。
建立暫時冒充表需要一個特殊的 sqlite3_test_control() 呼叫。與所有其他 SQLite API 不同,sqlite3_test_control() 介面可能會在不同的版本間進行不相容的變更,因此以下所述的機制無法保證在未來的 SQLite 版本中仍然有效。SQLite 開發人員並不認為這是一個問題,因為應用程式不應該使用冒充表。冒充表只用於分析和測試。
若要建立暫時冒充表,請先呼叫 sqlite3_test_control() 如下所示
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 1, tnum);
「db」參數是指向 資料庫連線 的指標。「main」參數是要建立冒充表的架構名稱。「1」參數會啟用冒充表機制。「tnum」是冒充表應鏡像的索引的根頁面。
在上述 sqlite3_test_control() 呼叫之後,執行 CREATE TABLE 陳述式,定義冒充表。在啟用冒充機制的情況下,這個 CREATE TABLE 陳述式不會建立真正的表,而是只在 SQLite 的內部符號表中加入一個項目。請注意,CREATE TABLE 陳述式必須符合索引的正確格式。如果冒充表的欄位數目不正確,或者不是 WITHOUT ROWID 表,或者與索引 B 樹不相容,則在使用冒充表時會產生 SQLITE_CORRUPT 錯誤。
執行 CREATE TABLE 陳述式後,請依下列方式停用冒充機制
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, "main", 0, 0);
換句話說,執行相同的 sqlite3_test_control() 呼叫,但將最後兩個參數變更為零。
如上所述,將冒充表格載入 SQLite 的內部架構後,冒充表格便可用作任何其他表格。但冒充表格只會對建立它的資料庫連線可見。不會對磁碟上的資料庫檔案進行任何變更。而冒充表格會在下次載入架構時消失。
自 SQLite 3.16.0 (2017-01-02) 起,命令列 shell 包含一個點指令「.imposter」,可執行設定暫時冒充表格的所有工作。暫時冒充表格可依下列方式建構,而非執行多個 sqlite3_test_control() 呼叫,並找出並呼叫相容的 CREATE TABLE 陳述式
.imposter t1bc t2
當然,將範例中顯示的「t1bc」和「t2」替換為所需的索引和冒充表格名稱。.imposter 指令會讀取「t1bc」索引的架構,使用該資訊為冒充表格建構相容的 CREATE TABLE 陳述式,然後執行所有必要的呼叫,以自動建立暫時冒充表格。
冒充表格機制是 SQLite 的威力分析和偵錯工具。但與所有鋒利的工具一樣,如果使用不當,它也可能很危險,並可能導致資料庫檔案損毀。請勿嘗試在應用程式中使用冒充表格。冒充表格旨在供專家在實驗室中使用。
此頁面最後修改於 2022-01-08 05:02:57 UTC