SQLite 虽然支持外键约束,但是它的外键约束默认情况是关闭的,需要每次操作数据库的时候传入 PRAGMA foreign_keys=1; 手动开启,如果不开启的话,即使数据库中添加了外键约束,在操作数据的时候也不会去检查,所以有必要编译出一个默认就支持外键约束的 SQLite 版本。

首先从 SQLite 网站上下载其源码,我使用的是 SQLite 3.6.0 的集合版本,点击立即下载。 下载完成后,解压到本地。在里面找到 sqlite3.c,就是我们要修改的文件。

首先阐述一下 SQLite 外键约束的控制原理。SQLite 3 使用一个结构体值存储各种属性状态,其中,SQLITE_ForeignKeys 控制外键约束,所以我们只需要使其始终为 1 即可。

在源码中有这样一段:

1
2
3
#if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS
             | SQLITE_ForeignKeys
#endif

这一段通过 SQLITE_DEFAULT_FOREIGN_KEYS 的宏定义,控制是否将 SQLITE_ForeignKeys 包含在结构体属性中,所以我们只需要将宏设为 1 ,就可以实现想要的效果了。

在官方文档中有说明,Foreign key 必须在宏 SQLITE_OMIT_FOREIGN_KEYSQLITE_OMIT_TRIGGER 均未定义的情况下才起作用,所以我们将宏定义放在它们未定义的域中,即

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/************** Begin file fkey.c ********************************************/
/*
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used by the compiler to add foreign key
** support to compiled SQL statements.
*/
/* #include "sqliteInt.h" */
 
#ifndef SQLITE_OMIT_FOREIGN_KEY
#ifndef SQLITE_OMIT_TRIGGER
 
// 新增了下面这一句
#define SQLITE_DEFAULT_FOREIGN_KEYS 1
 
// ...

然后在解压出来的目录中,使用 ./configure; make编译,编译会生成 sqlite3.exe ,这就是默认支持外键约束的 SQLite 了,命令行运行,在其中执行 PRAGMA foreign_keys,输出结果为 1,证明我们的修改生效了。