SQlite資料庫的C編程介面(六) 傳回值和錯誤碼(Result Codes
and Error Codes) by斜風細雨QQ:253786989 2012-02-07
標準碼(Standard Codes)
下面是標準的傳回值和錯誤碼定義:
#define SQLITE_OK 0 /* Successful result *//* beginning-of-error-codes */#define SQLITE_ERROR 1 /* SQL error or missing database */#define SQLITE_INTERNAL 2 /* 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 sqlite3_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 /* Unknown opcode in sqlite3_file_control() */#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 /* Database is empty */#define SQLITE_SCHEMA 17 /* The database schema changed */#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */#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_FORMAT 24 /* Auxiliary database format error */#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */#define SQLITE_NOTADB 26 /* File opened that is not a database file */#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */#define SQLITE_DONE 101 /* sqlite3_step() has finished executing *//* end-of-error-codes */
其中有些常量只由具體的某個函數返回,比如SQLITE_RANGE只會由sqlite3_bind_xxx函數返回。還有一些常量,比如SQLITE_ERROR只能說明函數在執行過程中發生了錯誤,但無法知道錯誤發生的原因。
SQLITE_MISUSE代表API被誤用。比如一條語句在sqlite3_step函數執行之後,沒有被重設之前,再次給其綁定參數,這時bind函數就會返回SQLITE_MISUSE。
擴充碼(Extended Codes)
標準錯誤碼對於錯誤發生的原因,所提供的資訊比較少。所以有時候,我們會使用擴充的錯誤碼。擴充錯誤碼是以標準錯誤碼為基礎,其低階位元組就是原本的標準錯誤碼,然後在其高階位元組“或”上附加資訊,描述錯誤發生的細節。
int sqlite3_extended_result_codes(sqlite3*, int onoff);
因為考慮到客戶舊程式的相容性問題,預設情況下,這些擴充的錯誤碼是沒有啟用的。程式員可以通過sqlite3_extended_result_codes函數啟用或者關閉擴充錯誤碼。
下面是所有的擴充錯誤碼(其中大部分用來描述SQLITE_IOERR):
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8))#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8))#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8))#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8))#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8))#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8))#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8))#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8))#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8))#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8))#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8))#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8))#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8))#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8))#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8))#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
Error相關函數(Error Functions)
int sqlite3_extended_result_codes(sqlite3*, int onoff);
針對某個資料庫連接,啟用或關閉擴充錯誤碼的使用。通過給sqlite3_extended_result_codes函數的第2個參數傳遞非零值來啟用擴充錯誤碼。該函數總是返回SQLITE_OK,沒有什麼途徑可以擷取擴充錯誤碼當前是否啟用或關閉。
int sqlite3_errcode(sqlite3 *db);
如果某個資料庫函數操作沒有返回SQLITE_OK,那麼可以隨後調用該函數擷取錯誤碼。預設情況下它返回標準錯誤碼,如果當前資料庫連接已經啟用了擴充錯誤碼,那麼該函數也可能會返回一個擴充的錯誤碼。
int sqlite3_extended_errcode(sqlite3 *db);
與sqlite3_errcode函數類似,只不過該函數只會返回擴充的錯誤碼。
const char *sqlite3_errmsg(sqlite3*);const void *sqlite3_errmsg16(sqlite3*);
返回錯誤碼字串,使用UTF-8或者UTF-16編碼。程式員應該在調用這兩個函數,擷取錯誤碼資訊之後立刻使用,或者做一個拷貝。因為下一個資料庫操作就可能會導致返回的字串指標失效。
SQlite錯誤處理不能夠同時處理多個錯誤,比如某個API函數調用發生了錯誤,而程式員沒有對該錯誤進行檢查處理,那麼下一次API函數調用就很可能返回SQLITE_MISUSE,表明程式試圖使用一個無效的資料結構。所以程式員應該在每次API函數調用之後檢查和處理任何可能發生的錯誤。
另外,如果多個線程分享同一個資料庫連接,最好將核心的API調用和錯誤處理部分的代碼封裝在關鍵代碼區(critical section)中。程式員可以使用sqlite3_db_mutex函數擷取資料庫連接的互斥鎖指標(一個指向sqlite3_mutex對象的指標)。
V2版本的prepare函數(Prepare v2)
下表是原版本的prepare函數和v2版本的prepare函數的比較:
V2版本的prepare函數對於錯誤處理更簡潔,還有上表中列出的關於schema的優點,所以推薦使用v2版本的prepare函數。
事務和錯誤(Transactions and Errors)
通常,SQlite操作處於自動認可模式。SQlite自動把每一個SQL命令封裝進事務中。如果每條語句都被封裝進它自己的事務中,那錯誤恢複就簡單了。任何時候只要SQLite發現它自己處於錯誤狀態,只要簡單的復原當前事務就可以了。這樣就可以有效取消當前SQL命令,並使資料庫回到出錯之前的狀態。
然而,一旦BEGIN TRANSACTION命令執行,SQlite就不在處於自動認可模式。一個事務被開啟,將一直保持開啟狀態直到END TRANSACTION或者COMMIT TRANSACTION命令執行。這就允許多條SQL命令封裝進一個事務中,使一系列離散的命令要麼全都執行,要麼都不執行(原子操作),不過這也限制了SQLite的錯誤恢複。
當一個顯示的(explicit)事務執行過程中遇到一個錯誤,SQLite試圖取消剛剛執行的語句。不幸的是,這並不總是可能的。如果事情很糟,SQlite有時候只能回退整個當前事務,沒有其他選擇。
最有可能導致復原的錯誤是SQLITE_FULL(資料庫或磁碟空間已滿),SQLITE_IOERR(磁碟IO錯誤或檔案被鎖定),SQLITE_BUSY(資料庫鎖定),SQLITE_NOMEM(記憶體不足),SQLITE_INTERRUPT(中斷)。如果程式正在執行一個顯示事務,並且收到這些錯誤之一,那就要準備好處理可能將發生的交易回復。
int sqlite3_get_autocommit(sqlite3*);
通過該函數,可以擷取當前的提交狀態。如果返回非0值,則資料庫處於自動認可(atutoconmit)模式。如果返回0,則資料庫正處於一個顯示事務之中(the database is currently inside an explicit transaction)。
如果SQlite資料庫被強製做了一次完全交易回復操作,則資料庫將再次變為事務自動認可模式。如果資料庫不在自動認可模式,則它肯定處於一個事務之中,表明並不需要復原。
SQlite資料庫的C編程介面(六) 傳回值和錯誤碼(Result Codes
and Error Codes) by斜風細雨QQ:253786989 2012-02-07