int sqlite3changeset_apply( sqlite3 *db, /* Apply change to "main" db of this handle */ int nChangeset, /* Size of changeset in bytes */ void *pChangeset, /* Changeset blob */ int(*xFilter)( void *pCtx, /* Copy of sixth arg to _apply() */ const char *zTab /* Table name */ ), int(*xConflict)( void *pCtx, /* Copy of sixth arg to _apply() */ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ sqlite3_changeset_iter *p /* Handle describing change and conflict */ ), void *pCtx /* First argument passed to xConflict */ ); int sqlite3changeset_apply_v2( sqlite3 *db, /* Apply change to "main" db of this handle */ int nChangeset, /* Size of changeset in bytes */ void *pChangeset, /* Changeset blob */ int(*xFilter)( void *pCtx, /* Copy of sixth arg to _apply() */ const char *zTab /* Table name */ ), int(*xConflict)( void *pCtx, /* Copy of sixth arg to _apply() */ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ sqlite3_changeset_iter *p /* Handle describing change and conflict */ ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, /* OUT: Rebase data */ int flags /* SESSION_CHANGESETAPPLY_* flags */ );
將變更集或修補程式集套用至資料庫。這些函式會嘗試使用透過第二和第三個引數傳遞的變更集中找到的變更來更新附加至處理程序 db 的「主要」資料庫。
傳遞給這些函式的第四個引數 (xFilter) 是「篩選器回呼」。如果它不是 NULL,則對於變更集中至少受到一個變更影響的每個資料表,會以資料表名稱作為第二個引數,並將作為第六個引數傳遞的內容指標副本作為第一個引數,來呼叫篩選器回呼。如果「篩選器回呼」傳回零,則不會嘗試將任何變更套用至資料表。否則,如果傳回值是非零或 xFilter 引數為 NULL,則會嘗試套用與資料表相關的所有變更。
對於未被篩選器回呼排除的每個資料表,此函式會測試目標資料庫是否包含相容的資料表。如果符合下列所有條件,則資料表會被視為相容
如果沒有相容的表格,這並非錯誤,但與表格相關的變更都不會套用。會透過 sqlite3_log() 機制發出警告訊息,錯誤代碼為 SQLITE_SCHEMA。變更集中每個表格最多只會發出一個這樣的警告。
對於每個有相容表格的變更,系統會嘗試根據 UPDATE、INSERT 或 DELETE 變更修改表格內容。如果無法順利套用變更,可能會呼叫傳遞給 sqlite3changeset_apply() 作為第五個參數的衝突處理函式。以下說明衝突處理函式在每種類型的變更中呼叫的確切時機。
與 xFilter 參數不同,xConflict 不能傳遞 NULL。傳遞任何內容(有效函式指標除外)作為 xConflict 參數,其結果是未定義的。
每次呼叫衝突處理函式時,它都必須傳回 SQLITE_CHANGESET_OMIT、SQLITE_CHANGESET_ABORT 或 SQLITE_CHANGESET_REPLACE 之一。只有當傳遞給衝突處理函式的第二個參數為 SQLITE_CHANGESET_DATA 或 SQLITE_CHANGESET_CONFLICT 時,才能傳回 SQLITE_CHANGESET_REPLACE。如果衝突處理函式傳回非法值,任何已進行的變更都會回滾,而對 sqlite3changeset_apply() 的呼叫會傳回 SQLITE_MISUSE。sqlite3changeset_apply() 會根據衝突處理函式的每次呼叫傳回的值採取不同的動作。有關詳細資訊,請參閱三個 可用傳回值 的文件。
如果找到具有相符主鍵值的行,但非主鍵欄位中有一個或多個欄位包含與變更集中儲存的原始行值不同的值,則會呼叫衝突處理函式,並將 SQLITE_CHANGESET_DATA 作為第二個引數。如果資料庫表格的欄位數多於變更集中記錄的欄位數,則只會將那些非主鍵欄位的數值與目前的資料庫內容進行比較,而會忽略任何尾隨的資料庫表格欄位。
如果在資料庫中找不到具有相符主鍵值的列,則會呼叫衝突處理函式,並將 SQLITE_CHANGESET_NOTFOUND 傳遞為第二個引數。
如果嘗試執行 DELETE 作業,但 SQLite 傳回 SQLITE_CONSTRAINT(僅在違反外來鍵約束時才會發生),則會呼叫衝突處理函式,並將 SQLITE_CHANGESET_CONSTRAINT 傳遞為第二個引數。這包括由於先前呼叫衝突處理函式傳回 SQLITE_CHANGESET_REPLACE 而嘗試執行 DELETE 作業的情況。
如果嘗試新增列失敗,因為資料庫中已包含具有相同主鍵值的列,則會呼叫衝突處理函式,並將第二個引數設定為 SQLITE_CHANGESET_CONFLICT。
如果嘗試新增列失敗,因為發生其他約束衝突(例如 NOT NULL 或 UNIQUE),則會呼叫衝突處理函式,並將第二個引數設定為 SQLITE_CHANGESET_CONSTRAINT。這包括由於先前呼叫衝突處理函式傳回 SQLITE_CHANGESET_REPLACE 而重新嘗試執行新增作業的情況。
如果找到具有相符主鍵值的列,但一個或多個已修改非主鍵欄位包含與儲存在變更集中原始列值不同的值,則會呼叫衝突處理函式,並將 SQLITE_CHANGESET_DATA 作為第二個引數。由於 UPDATE 變更僅包含要修改的非主鍵欄位值,因此只有這些欄位需要與原始值相符,才能避免 SQLITE_CHANGESET_DATA 衝突處理常式回呼。
如果在資料庫中找不到具有相符主鍵值的列,則會呼叫衝突處理函式,並將 SQLITE_CHANGESET_NOTFOUND 傳遞為第二個引數。
如果嘗試 UPDATE 作業,但 SQLite 傳回 SQLITE_CONSTRAINT,則會呼叫衝突處理函式,並將 SQLITE_CHANGESET_CONSTRAINT 傳遞為第二個引數。這包括在衝突處理函式傳回 SQLITE_CHANGESET_REPLACE 之後嘗試 UPDATE 作業的情況。
從 xConflict 回呼中執行 SQL 陳述式(包括寫入與回呼相關的表格)是安全的。這可用於進一步自訂應用程式的衝突解決策略。
這些函式所做的所有變更都封裝在儲存點交易中。如果發生任何其他錯誤(除了嘗試寫入目標資料庫時發生約束失敗),則會回滾儲存點交易,將目標資料庫還原至其原始狀態,並傳回 SQLite 錯誤碼。
如果輸出參數 (ppRebase) 和 (pnRebase) 為非 NULL,且輸入為變更集(而非修補程式集),則 sqlite3changeset_apply_v2() 可能會將 (*ppRebase) 設定為指向在傳回之前可能與 sqlite3_rebaser API 緩衝區一起使用的「重新設定基準」。在此情況下,(*pnRebase) 會設定為緩衝區的大小(以位元組為單位)。呼叫者有責任最終使用 sqlite3_free() 釋放任何此類緩衝區。僅當在套用修補程式集時遇到一個或多個衝突時,才會配置並填入緩衝區。請參閱 sqlite3_rebaser API 周圍的註解以取得進一步詳細資料。
sqlite3changeset_apply_v2() 及其串流等效項的行為可以透過傳遞 支援的旗標 組合作為第 9 個參數來修改。
請注意,sqlite3changeset_apply_v2() API 仍為實驗性質,因此可能會變更。