背景
SQLite 是 一個 常用於 嵌入式平台的 輕量級的 關系型數據庫。
我們已經介紹了 移植 SQLite 3 ,這一講我們來介紹它的開發,這里僅僅涉及最基本的開發。
高級api:https://blog.csdn.net/yxtxiaotian/article/details/89037128
數據庫有關概念
在介紹開發之前,我們需要明確有關概念。
數據庫
(DataBase): “按照數據結構來組織、存儲和管理數據的倉庫”。是一個長期存儲在計算機內的、有組織的、可共享的、統一管理的大量數據的集合。
數據庫管理系統
數據庫概念的演變與誕生經歷了漫長的發展過程,從最開始的人工管理,到文件系統,再到數據庫系統。每一個階段的到來都伴隨着新的技術突破。
數據庫管理系統(DataBase Managerment System, DBMS):管理數據庫的一個軟件,它充當所有數據的知識庫,並對它的存儲、安全、一致性、並發操作、恢復和訪問負責。是對數據庫的一種完整和統一的管理和控制機制。DBMS有一個數據字典(有時被稱為系統表),用於貯存它擁有的每個事物的相關信息,例如名字、結構、位置和類型,這種關於數據的數據也被稱為元數據(metadata)。
DBMS支持的3種數據模型:(這里不提 面向對象模型)
- 層次模型:若用圖來表示,層次模型是一棵倒立的樹。在現實世界中,事物之間的聯系更多的是非層次關系的,用層次模型表示非樹型結構是很不直接的。
在數據庫中,滿足以下條件的數據模型稱為層次模型:
a.有且僅有一個節點無父節點,這個節點稱為根節點;
b.其他節點有且僅有一個父節點。桌面型的關系模型數據庫
- 網狀模型:網狀模型是一個網絡。在數據庫中,滿足以下兩個條件的數據模型稱為網狀模型。網狀模型構成了比層次結構復雜的網狀結構,適宜表示多對多的聯系。
a.允許一個以上的節點無父節點;
b.一個節點可以有多於一個的父節點。
- 關系模型:以二維表的形式表示實體和實體之間聯系的數據模型稱為關系數據模型。
從模型的三要素角度看,關系模型的內容為:
a.數據結構:一張二維表格。
b.數據操作:數據表的定義、檢索、維護、計算等。
c.數據約束條件:表中列的取值范圍即域值的限制條件。
表
關系模型數據庫采用表組織數據(表稱為“關系”),一個數據庫由許多個表組成,多個表數據之間存在着關系,在這些表上的數據操作依賴於關系,關系用來描述多個表之間的數據依存,包括了一對一、一對多、多對多的關系
字段
在數據庫中,大多數時,表的“列”稱為“字段”(Attribute) ,每個字段包含某一專題的信息。就像“通訊錄”數據庫中,“姓名”、“聯系電話”這些都是表中所有行共有的屬性,所以把這些列稱為“姓名”字段和“聯系電話”字段。
字段 = 字段名 + 類型
sqlite 中的 數據類型
- NULL :空類型(相當exel表格當中的:常規格式)
- INTEGER :整型(整型數據:24 366 14)
- REAL :IEEE浮點數(3.24 36.14)
- TEXT :文本型(表示字符:"224")
- BLOB :按照二進制值存儲(圖片,音頻)
主關鍵字(primary key):
表中的一個或多個字段,它的值用於唯一地標識表中的某一條記錄。在兩個表的關系中,主關鍵字用來在一個表中引用來自於另一個表中的特定記錄。主關鍵字是一種唯一關鍵字,表定義的一部分。一個表的主鍵可以由多個關鍵字共同組成,並且主關鍵字的列不能包含空值。主關鍵字是可選的,並且可在 CREATE TABLE
或 ALTER TABLE
語句中定義。一個表中只能有一個主鍵,最好為每個表都設置一個主鍵。
開發流程
在Sqlite提供了兩個重要對象:database_connection(數據庫連接)和prepared_statement)處理命令:
database_connection:
- database_connection對象是由sqlite3_open接口函數創建並返回的。
- 在其他應用程序調用Sqlite3相關接口時,都需要這個對象作為輸入來完成操作。
prepared_statement:
- 編譯后的SQL語句。是select、insect、updata···
- 所有和SQL語句執行相關的函數也都需要 該對象作為輸入參數以完成指定的SQL操作。
0)創建數據庫、在數據庫中創建表
1)打開數據庫
2)在表中插入數據、修改、查詢、刪除一行記錄
3)關閉數據庫
有關函數
所有的函數都需要包含:#include "sqlite3.h"
,以下不再贅述。
數據庫的操作無非就是CURD,我們一個個來看
打開/創建 數據庫 sqlite3_open
int sqlite3_open(const char *filename,sqlite3 **db);
int sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **db /* OUT: SQLite db handle */
);
int sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **db, /* OUT: SQLite db handle */
int flags, /* Flags */
const char *zVfs /* Name of VFS module to use */
);
描述:打開對應的數據庫文件,如果不存在則創建
參數解析:
filename:數據庫文件名
db:用於接收數據庫對象的指針
flags :
- SQLITE_OPEN_NOMUTEX: 設置數據庫連接運行在多線程模式(沒有指定單線程模式的情況下)
- SQLITE_OPEN_FULLMUTEX:設置數據庫連接運行在串行模式。
- SQLITE_OPEN_SHAREDCACHE:設置運行在共享緩存模式。
- SQLITE_OPEN_PRIVATECACHE:設置運行在非共享緩存模式。
- SQLITE_OPEN_READWRITE:指定數據庫連接可以讀寫。
- SQLITE_OPEN_CREATE:如果數據庫不存在,則創建。
zvfs : 一個 sqlite3_vfs 對象(定義了數據庫使用的操作系統接口),如果為NULL則使用默認值
注:傳遞db時不需要為db申請內存。
例程:
int main(int argc, char *argv[])
{
int ret;
sqlite3 *db = NULL;
//打開數據庫
ret = sqlite3_open("example.db",&db);
if(ret != SQLITE_OK)
{
printf("sqlite3_open failure!\n");
printf("%s\n", sqlite3_errmsg(db));
return -1;
}
return 0;
}
關閉數據庫 sqlite3_close
int sqlite3_close(sqlite3* db);
描述:關閉數據庫
參數解析:db : 持有數據庫對象的指針
返回值:返回0
例程:
ret = sqlite3_close(db);
獲取錯誤信息 sqlite3_errmsg / sqlite3_errcode
const char *sqlite3_errmsg(sqlite3* db);
int sqlite3_errcode(sqlite3 *db)
描述:返回操作數據庫時的錯誤信息
參數解析:db : 持有數據庫對象的指針
注:使用
sqlite3_close
以后調用sqlite3_errmsg
會導致library routine called out of sequence
返回值:成功時返回對應類型的錯誤信息。
例程:
int main(int argc, char *argv[])
{
int ret;
sqlite3 *db = NULL;
ret = sqlite3_open("example.db",&db);
if(ret != SQLITE_OK)
{
printf("sqlite3_open failure!\n");
printf("%s\n", sqlite3_errmsg(db)); // 打印錯誤信息
return -1;
}
return 0;
}
格式化SQLite語句 sqlite3_mprintf
char *sqlite3_mprintf(const char*,...);
void sqlite3_free(void*);
描述:
-
將結果寫入到sqlite3_malloc()獲取的內存中,例程返回的字符串應該使用sqlite3_free()進行釋放,如果無法申請到足夠的內存,則會返回NULL指針;
-
它同c庫函數 sprintf()類似,實現一些額外的格式化。對所有常用的printf()格式化選項都適用。另外還有非常用選項:%q, %Q, %z;
-
%q選項的作用類似於%s,它會替換了參數列表中以空字符結尾的字符串%q,同時他會將單引號字符轉義,有助於防止SQL注入攻擊
作為一般規則,在將文本插入字符串文字時,應始終使用%q而不是%s。
- %Q選項的作用類似於%q,除了它還在整個字符串的外部添加單引號。此外,如果參數列表中的參數是NULL指針,則%Q替換文本“NULL”(不帶單引號)
- “%z”格式化選項的作用類似於“%s”,但添加了在讀取字符串並將其復制到結果中之后,在輸入字符串上調用
sqlite3_free
。 - 當需要插入的字符為NULL時,%s 並沒有將NULL插入到表中,但是%q, %Q能夠將NULL插入到表中,只是大小寫不一樣
執行 SQLite 語句
一共有6個函數(3組) 可以實現執行語句: sqlite3_exec
、 sqlite3_get_table/sqlite3_free_table
、sqlite3_prepare_v2/sqlite3_step/sqlite3_finalize
它們的區別在於
(1).sqlite3_exec方式接口使用很簡單,實現同樣的功能,比sqlite3_perpare_v2接口代碼量少。
(2).sqlite3_prepare方式更高效,因為只需要編譯一次,就可以重復執行N次。
(3).sqlite3_prepare方式支持參數化SQL。
鑒於兩種方式的差異,對於簡單的PRAGMA設置語句(PRAGMA cache_size=2000),事務設置語句(BEGIN TRANSACTION,COMMIT,ROLLBACK)使用sqlite3_exec方式,更簡單;而對於批量的更新、查詢語句,則使用sqlite3_prepare方式,更高效。
用ltrace跟蹤
sqlite3_get_table
時,發現效率比較低,因為它封裝了sqlite3_exec
這些函數,而sqlite3_exec
又調用了sqlite3_prepare
等,看來還是得在后兩者中選擇一個了。不過如果查詢不是很多,應該說來sqlite3_get_table就好了,而且使用簡單。
sqlite3_exec
int sqlite3_exec(
sqlite3* db, const char *sql,
int (*callback)(void*,int,char**,char**),
void *arg, char **errmsg
);
int callback(void *execarg, int ncols, char ** values, char **attribute);
/*
execarg : sqlite3_exec() 傳進來的參數
ncols : 字段個數
values : 字段值
attribute:字段名
*/
描述:執行sql指定的數據庫命令操作。
參數解析:
db :持有數據庫對象的指針
sql :SQL命令,可以有多條命令組成
callback:執行完該函數的回調函數
arg : 執行callback回調函數的參數(execarg)
errmsg : 獲取函數錯誤是的錯誤碼
注意:每成功執行的一次select執行操作,就會調用一次回調函數;插入,刪除,更新不執行回調函數。 這個特征具體可以參考sqlite3交互式程序。
sqlite3_exec 通常用於執行不返回數據的查詢,如insert、update、delete
#include "sqlite3.h"
int sqlite_callback(void *data, int ncols, char ** values, char **attribute)
{
printf("sqlite_callback\n");
printf("Data addr is %p\n", data);
printf("ncols is %d\n", ncols);
for(int i = 0; i< ncols; i++)
{
printf("%p %s %s\n", attribute, attribute[i], values[i]);
}
printf("\n");
printf("\n");
return 0;
}
int main(int argc, char *argv[])
{
int ret;
sqlite3 *db;
//打開數據庫
ret = sqlite3_open("example.db",&db);
printf("%d\n", ret);
if(ret != SQLITE_OK)
{
printf("sqlite3_open failure!\n");
printf("%s\n", sqlite3_errmsg(db));
return -1;
}
char *errmsg;
// 執行 n 次 回調函數
char *command_select = "SELECT * FROM table1";
int data = 2;
printf("%p\n", &data);
ret = sqlite3_exec(db, command_select, sqlite_callback, &data,0);
if(ret != SQLITE_OK)
{
printf("sqlite3_open failure!\n");
return -1;
}
ret = sqlite3_close(db);
return 0;
}
sqlite3_get_table/sqlite3_free_table
int SQLite3_get_table(
sqlite3 *db, const char *sql,
char ***result, int *nrow, int *ncolumn, char **errmsg);
void sqlite3_free_table(char **result);
描述:功能與sqlite3_exec
一樣,只是無需回調函數處理,使用get以后要free,不然會導致內存泄漏。該函數接收SQL語句返回的所有記錄,由於結果集可能非常大,會導致內存撐爆,因此對於大結果集的查詢,不建議采用這種方式。 (這是一個歷史遺留的接口,已經不推薦使用)
如果sqlite3_get_table在內部調用的 sqlie3_exec 發生錯誤時,錯誤信息無法通過sqlite3_errcode/sqlite3_errmsg獲取;
參數解析:
db : 持有數據庫對象的指針
sql : SQL語句
result :存放結果集的指針
nrow : 存放行數獲取結果的容器
ncolumn :存放列數獲取結果的容器
errmsg:存放錯誤信息的指針
例程
#include <stdio.h>
#include <string.h>
#include "sqlite3.h"
int main(void)
{
int ret,i,j;
sqlite3 *db = NULL;
char *errmsg;
char **result;
int nrow, ncolumn;
// 打開數據庫,若數據庫不存在,則創建
ret = sqlite3_open("example.db",&db);
if(ret != SQLITE_OK)
{
printf("sqlite3_open failure!\n");
return -1;
}
// 創建表、執行創建表的命令
char *sql = "CREATE TABLE IF NOT EXISTS student(id integer primary key, name text,age integer,sex text,phone text);";
ret = sqlite3_exec(db,sql,0,0,&errmsg);
// 執行命令,並獲取結果
sqlite3_get_table(db, "SELECT * FROM student;", &result, &nrow, &ncolumn, &errmsg);
printf("nrow = %d\n", nrow); //行 --> 6
printf("ncolumn = %d\n", ncolumn);//列 --> 5
for(i=0; i<nrow; i++)
{
for(j=0; j<ncolumn; j++)
{
printf("字段:%s 字段值:%s\n",presult[j], presult[ncolumn] );
index++;
}
printf("===================================\n");
}
//釋放空間
sqlite3_free_table(result);
sqlite3_close(db);
return 0;
}
sqlite3_prepare_v2/sqlite3_step/sqlite3_finalize
sqlite3_exec實際上是將編譯,執行進行了封裝,與之等價的一組函數是
sqlite3_prepare_v2()
,sqlite3_step()
和sqlite3_finalize()
。
sqlite3_prepare_v2()
編譯SQL語句生成VDBE執行碼,sqlite3_step()
執行,sqlite3_finalize()
關閉語句句柄,釋放資源。
int sqlite3_prepare_v2 (
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **stmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
int sqlite3_step(sqlite3_stmt* stmt);
描述:如果既不想寫回調函數,又想避免sqlite3_get_table
之后麻煩的一維數組遍歷,那么利用sqlite3_prepare_v2執行sql select
語句,然后sqlite3_step
遍歷select
執行的返回結果是一個非常方便的解決方案。
當然,你必須要明白
sqlite3_prepare_v2
不僅僅能夠執行table的query selection,也能方便地進行sql Delete, Insert, Update
等其他一些操作。它能幫你把sql語句的執行操作變的更加優雅。
參數詳解:
db : 持有數據庫對象的指針
zSql : SQL語句,新舊版本使用不同的編碼(正常使用即可)
nByte:若為負,從zSql 中取出,直到第一個0終止符終止;如果為非負,它則是這個函數能讀取Zsql的最大字節數。
stmt:能夠作為sqlite3_step()
執行的編譯好的准備語句的指針,如果錯誤發生,它被置為NULL,如假如輸入的文本不包括SQL語句,調用過程必須負責在編譯好的sql語句完成使用后使用sqlite3_finalize()
刪除它。
pzTail:上面提到zSql在遇見終止符或者是達到設定的nByte之后結束,假如zSql還有剩余的內容,那么這些剩余的內容被存放到pZTail中,不包括終止符.
例程1 : 簡單做一下查詢
const char *selectSql="select id,name from persons";
int id;
char *name;
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(db, selectSql, -1, &statement, NULL) !=SQLITE_OK)
{
printf("select error: %s", sqlie3_errmsg(db));
}
while (sqlite3_step(statement)==SQLITE_ROW)
{
int id=sqlite3_column_int(statement, 0);
name = (char *)sqlite3_column_text(statement, 1);
printf("row >>id %d, name %s",id, name); // 由於 這個接口使用了 UTF-8 所以打印中文可能會有亂碼
}
sqlite3_finalize(statement);
例程2 : 執行多sql
prepare方式執行多sql的例子,pNext初始化在sql語句首部,執行完一個sql后,移動到下一個sql首部。
const char *pNext = (const char *)sql;
while (pNext && strlen(pNext) > 0) {
rc = sqlite3_prepare_v2(db, pNext, -1, &stmt, &pNext);
if(SQLITE_OK != rc){
錯誤處理
break;
}
rc = sqlite3_step(stmt);
if(SQLITE_OK != rc && SQLITE_DONE != rc){
錯誤處理
break;
}
rc = SQLITE_OK;
/*統計影響記錄數目*/
resultCount += sqlite3_changes(db);
/* 清理語句句柄,准備執行下一個語句*/
sqlite3_finalize(stmt);
}
例程3 : 查詢語句
prepare方式同樣支持查詢語句,主要分為3個階段,編譯,執行和結果集處理。前面更新SQL部分已經描述了prepare的基本步驟,這里主要講結果集處理部分。首先通過sqlite3_column_count()
可以得到結果集的列數目,通過sqlite3_column_type()
可以得到具體某列的存儲類型,方便我們調用合適的sqlite3_column_xxx接口處理字段值。主要有以下幾類:
- sqlite3_column_int
- sqlite3_column_int64
- sqlite3_column_double
- sqlite3_column_text
- sqlite3_column_blob
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
//獲取列數目
int n_columns = sqlite3_column_count(stmt);
do{
ret = sqlite3_step(stmt);
if (ret == SQLITE_ROW)
{
//處理每一列
for (i = 0; i < n_columns; i++)
{
/*獲取列存儲類型*/
type = sqlite3_column_type(stmt,i);
switch(type)
{
case SQLITE_INTEGER:
/*處理整型*/
sqlite3_column_int(stmt,i);
break;
case SQLITE_FLOAT:
/*處理浮點數*/
sqlite3_column_double(stmt,i);
break;
case SQLITE_TEXT:
/*處理字符串*/
sqlite3_column_text(stmt,i);
break;
case SQLITE_BLOB:
/*處理二進制*/
sqlite3_column_blob(stmt, i));
break;
case SQLITE_NULL:
/*處理空*/
}
}
}
else if (ret == SQLITE_DONE) //結束
{
break;
}
}while(true);
例程4 : 參數綁定
SQLite通過prepare接口可以支持參數化的SQL語句,即帶問號的SQL語句。比如查詢語句select * from t where id=?
,或者插入語句 insert into t(a,b,c) values(?,?,?)
。通過參數化SQL,可以實現一次編譯多次執行的目的,由於問號是沒有意義的,因此需要調用sqlite3_bind_xxx接口來綁定具體的參數。主要有以下幾類:
- sqlite3_bind_int
- sqlite3_bind_int64
- sqlite3_bind_double
- sqlite3_bind_text
- sqlite3_bind_blob
- sqlite3_bind_null
關於綁定參數這里提一點,對於sqlite3_bind_text和sqlite3_bind_blob接口,綁定參數占據的存儲空間是否可以被SQLite重用。接口中通過最后一個參數指定,參數值可以為SQLITE_STATIC和SQLITE_TRANSIENT。
- SQLITE_STATIC:通知bind函數,參數使用空間是常量,不會改變,sqlite內部無需拷貝副本。
- SQLITE_TRANSIENT:通知bind函數,參數使用空間可能會改變,sqlite內部需要有自己的副本。
//begin a transaction
if(sqlite3_exec(pdb, "begin", NULL, NULL, &errmsg) != SQLITE_OK)
{
錯誤處理
return ERROR;
}
sqlite3_prepare_v2(pdb, "insert into t1 values(?,?,?);", &stmt);
for (i = 0; i < n_rows; i++)
{
for (j = 0; j < n_columns; j++)
{
switch(type)
{
case SQLITE_INTEGER:
/*處理整型*/
sqlite3_bind_int()
break;
case SQLITE_FLOAT:
/*處理浮點型*/
sqlite3_bind_double()
break;
case SQLITE_TEXT:
/*處理字符串類型*/
sqlite3_bind_text()
break;
case SQLITE_BLOB:
/*處理二進制類型*/
sqlite3_bind_blob
break;
case SQLITE_NULL:
sqlite3_bind_null(stmt, index);
break;
}
}
sqlite3_step(stmt); //執行
sqlite3_reset(stmt); //將已編譯的SQL語句恢復到初始狀態,保留語句相關的資源
}
sqlite3_finalize(stmt); //結束語句,釋放語句句柄
if(sqlite3_exec(pdb, "commit", NULL, NULL, &errmsg) != SQLITE_OK)
{
錯誤處理 return ERROR;
}
SQLite3 語法:
創建表
CREATE TABLE [IF NOT EXISTS] table_name(
column1 datatype PRIMARY KEY(one or more columns),
column2 datatype[,
column3 datatype,
.....
columnN datatype,]
);
刪除表
DROP TABLE database_name.table_name;
添加一行數據
INSERT INTO TABLE_NAME [(column1, column2, column3,...columnN)]
VALUES (value1, value2, value3,...valueN);
查詢
SELECT 語句用於從 SQLite 數據庫表中獲取數據,以結果表的形式返回數據。這些結果表也被稱為結果集。
SELECT column1, column2, columnN FROM table_name;
刪除數據
DELETE 查詢用於刪除表中已有的記錄。可以使用帶有 WHERE 子句的 DELETE 查詢來刪除選定行,否則所有的記錄都會被刪除。
DELETE FROM table_name WHERE [condition];
修改數據
SQLite 的 UPDATE 查詢用於修改表中已有的記錄。可以使用帶有 WHERE 子句的 UPDATE 查詢來更新選定行,否則所有的行都會被更新。
UPDATE table_name
SET column1 = value1, column2 = value2...., columnN = valueN
WHERE [condition];
交互式Sqlite3工具的使用
$ sqlite3 example.db # 運行sqlite3時順便打開一個數據庫
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> .tables
table1
sqlite> select * from table1;
100|text
101|text
102|text
103|text
104|text
105|text
106|text
107|text
108|text
109|text
sqlite>
附錄:sqlite3 錯誤碼表
#define SQLITE_OK 0 /* 成功 | Successful result */
/* 錯誤碼開始 */
#define SQLITE_ERROR 1 /* SQL錯誤 或 丟失數據庫 | SQL error or missing database */
#define SQLITE_INTERNAL 2 /* SQLite 內部邏輯錯誤 | 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 /* 某次 malloc() 函數調用失敗 | A malloc() failed */
#define SQLITE_READONLY 8 /* 嘗試寫入一個只讀數據庫 | Attempt to write a readonly database */
#define SQLITE_INTERRUPT 9 /* 操作被 sqlite3_interupt() 函數中斷 | Operation terminated by sqlite3_interrupt() */
#define SQLITE_IOERR 10 /* 發生某些磁盤 I/O 錯誤 | Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* 數據庫磁盤映像不正確 | The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* sqlite3_file_control() 中出現未知操作數 | 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 /* 傳遞給sqlite3_bind()的第二個參數超出范圍 | 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() 已經產生一個行結果 | sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() 完成執行操作 | sqlite3_step() has finished executing */
/* 錯誤碼結束 */