Skip to content

Commit 43bc191

Browse files
lilydjwgabonander
authored andcommitted
Add a "sqlite-unbundled" feature that dynamically links to system libsqlite3.so library (launchbadge#3507)
* Add a "sqlite-unbundled" feature that dynamically links to system libsqlite3.so library * update README abouot the newly-added `sqlite-unbundled` feature * Update README.md to make it clear with bulleted list Co-authored-by: Austin Bonander <[email protected]> * more cfg feature updates Co-authored-by: Austin Bonander <[email protected]> * update documentation in sqlx-sqlx/src/lib.rs too and also mention possible build time increasement. * cargo fmt * Add "sqlite-unbundled" feature to sqlx-cli * Add sqlite-unbundled to gituhb actions tests * cfg(feature = "sqlite") => cfg(any(feature = "sqlite", feature = "sqlite-unbundled")) * fix * CI: make sqlite-unbundled tests workaround required-features by duplicating the relevant test section * use an internal "_sqlite" feature to do the conditional compilation --------- Co-authored-by: Austin Bonander <[email protected]>
1 parent e710cda commit 43bc191

File tree

20 files changed

+68
-26
lines changed

20 files changed

+68
-26
lines changed

.github/workflows/sqlx.yml

+11-6
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ jobs:
117117
strategy:
118118
matrix:
119119
runtime: [async-std, tokio]
120+
linking: [sqlite, sqlite-unbundled]
120121
needs: check
121122
steps:
122123
- uses: actions/checkout@v4
@@ -125,7 +126,11 @@ jobs:
125126

126127
- uses: Swatinem/rust-cache@v2
127128
with:
128-
key: "${{ runner.os }}-sqlite-${{ matrix.runtime }}-${{ matrix.tls }}"
129+
key: "${{ runner.os }}-${{ matrix.linking }}-${{ matrix.runtime }}-${{ matrix.tls }}"
130+
131+
- name: Install system sqlite library
132+
if: ${{ matrix.linking == 'sqlite-unbundled' }}
133+
run: sudo apt-get install -y libsqlite3-dev
129134

130135
- run: echo "using ${DATABASE_URL}"
131136

@@ -135,7 +140,7 @@ jobs:
135140
- run: >
136141
cargo test
137142
--no-default-features
138-
--features any,macros,sqlite,_unstable-all-types,runtime-${{ matrix.runtime }}
143+
--features any,macros,${{ matrix.linking }},_unstable-all-types,runtime-${{ matrix.runtime }}
139144
--
140145
--test-threads=1
141146
env:
@@ -151,8 +156,8 @@ jobs:
151156
- run: >
152157
cargo build
153158
--no-default-features
154-
--test sqlite-macros
155-
--features any,macros,sqlite,_unstable-all-types,runtime-${{ matrix.runtime }}
159+
--test ${{ matrix.linking }}-macros
160+
--features any,macros,${{ matrix.linking }},_unstable-all-types,runtime-${{ matrix.runtime }}
156161
env:
157162
SQLX_OFFLINE: true
158163
SQLX_OFFLINE_DIR: .sqlx
@@ -163,8 +168,8 @@ jobs:
163168
- run: >
164169
cargo test
165170
--no-default-features
166-
--test sqlite-macros
167-
--features any,macros,sqlite,_unstable-all-types,runtime-${{ matrix.runtime }}
171+
--test ${{ matrix.linking }}-macros
172+
--features any,macros,${{ matrix.linking }},_unstable-all-types,runtime-${{ matrix.runtime }}
168173
env:
169174
DATABASE_URL: sqlite://tests/sqlite/sqlite.db
170175
SQLX_OFFLINE: true

Cargo.toml

+8-1
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,14 @@ runtime-tokio-rustls = ["runtime-tokio", "tls-rustls-ring"]
9898
# for conditional compilation
9999
_rt-async-std = []
100100
_rt-tokio = []
101+
_sqlite = []
101102

102103
# database
103104
any = ["sqlx-core/any", "sqlx-mysql?/any", "sqlx-postgres?/any", "sqlx-sqlite?/any"]
104105
postgres = ["sqlx-postgres", "sqlx-macros?/postgres"]
105106
mysql = ["sqlx-mysql", "sqlx-macros?/mysql"]
106-
sqlite = ["sqlx-sqlite", "sqlx-macros?/sqlite"]
107+
sqlite = ["_sqlite", "sqlx-sqlite/bundled", "sqlx-macros?/sqlite"]
108+
sqlite-unbundled = ["_sqlite", "sqlx-sqlite/unbundled", "sqlx-macros?/sqlite-unbundled"]
107109

108110
# types
109111
json = ["sqlx-macros?/json", "sqlx-mysql?/json", "sqlx-postgres?/json", "sqlx-sqlite?/json"]
@@ -250,6 +252,11 @@ name = "sqlite-macros"
250252
path = "tests/sqlite/macros.rs"
251253
required-features = ["sqlite", "macros"]
252254

255+
[[test]]
256+
name = "sqlite-unbundled-macros"
257+
path = "tests/sqlite/macros.rs"
258+
required-features = ["sqlite-unbundled", "macros"]
259+
253260
[[test]]
254261
name = "sqlite-derives"
255262
path = "tests/sqlite/derives.rs"

README.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,14 @@ be removed in the future.
183183

184184
- `mssql`: Add support for the MSSQL database server.
185185

186-
- `sqlite`: Add support for the self-contained [SQLite](https://sqlite.org/) database engine.
186+
- `sqlite`: Add support for the self-contained [SQLite](https://sqlite.org/) database engine with SQLite bundled and statically-linked.
187+
188+
- `sqlite-unbundled`: The same as above (`sqlite`), but link SQLite from the system instead of the bundled version.
189+
* Allows updating SQLite independently of SQLx or using forked versions.
190+
* You must have SQLite installed on the system or provide a path to the library at build time.
191+
See [the `rusqlite` README](https://github.com/rusqlite/rusqlite?tab=readme-ov-file#notes-on-building-rusqlite-and-libsqlite3-sys) for details.
192+
* May result in link errors if the SQLite version is too old. Version `3.20.0` or newer is recommended.
193+
* Can increase build time due to the use of bindgen.
187194

188195
- `any`: Add support for the `Any` database driver, which can proxy to a database driver at runtime.
189196

sqlx-cli/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ native-tls = ["sqlx/runtime-tokio-native-tls"]
5757
mysql = ["sqlx/mysql"]
5858
postgres = ["sqlx/postgres"]
5959
sqlite = ["sqlx/sqlite"]
60+
sqlite-unbundled = ["sqlx/sqlite-unbundled"]
6061

6162
# workaround for musl + openssl issues
6263
openssl-vendored = ["openssl/vendored"]

sqlx-cli/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ $ cargo install sqlx-cli --features openssl-vendored
1919

2020
# use Rustls rather than OpenSSL (be sure to add the features for the databases you intend to use!)
2121
$ cargo install sqlx-cli --no-default-features --features rustls
22+
23+
# only for sqlite and use the system sqlite library
24+
$ cargo install sqlx-cli --no-default-features --features sqlite-unbundled
2225
```
2326

2427
## Usage

sqlx-cli/src/database.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub async fn create(connect_opts: &ConnectOpts) -> anyhow::Result<()> {
1111
let exists = crate::retry_connect_errors(connect_opts, Any::database_exists).await?;
1212

1313
if !exists {
14-
#[cfg(feature = "sqlite")]
14+
#[cfg(feature = "_sqlite")]
1515
sqlx::sqlite::CREATE_DB_WAL.store(
1616
connect_opts.sqlite_create_db_wal,
1717
std::sync::atomic::Ordering::Release,

sqlx-cli/src/opt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ pub struct ConnectOpts {
258258
/// However, if your application sets a `journal_mode` on `SqliteConnectOptions` to something
259259
/// other than `Wal`, then it will have to take the database file out of WAL mode on connecting,
260260
/// which requires an exclusive lock and may return a `database is locked` (`SQLITE_BUSY`) error.
261-
#[cfg(feature = "sqlite")]
261+
#[cfg(feature = "_sqlite")]
262262
#[clap(long, action = clap::ArgAction::Set, default_value = "true")]
263263
pub sqlite_create_db_wal: bool,
264264
}

sqlx-core/src/any/kind.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub enum AnyKind {
1616
#[cfg(feature = "mysql")]
1717
MySql,
1818

19-
#[cfg(feature = "sqlite")]
19+
#[cfg(feature = "_sqlite")]
2020
Sqlite,
2121

2222
#[cfg(feature = "mssql")]
@@ -48,12 +48,12 @@ impl FromStr for AnyKind {
4848
Err(Error::Configuration("database URL has the scheme of a MySQL database but the `mysql` feature is not enabled".into()))
4949
}
5050

51-
#[cfg(feature = "sqlite")]
51+
#[cfg(feature = "_sqlite")]
5252
_ if url.starts_with("sqlite:") => {
5353
Ok(AnyKind::Sqlite)
5454
}
5555

56-
#[cfg(not(feature = "sqlite"))]
56+
#[cfg(not(feature = "_sqlite"))]
5757
_ if url.starts_with("sqlite:") => {
5858
Err(Error::Configuration("database URL has the scheme of a SQLite database but the `sqlite` feature is not enabled".into()))
5959
}

sqlx-macros-core/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ _tls-native-tls = ["sqlx-core/_tls-native-tls"]
1818
_tls-rustls-aws-lc-rs = ["sqlx-core/_tls-rustls-aws-lc-rs"]
1919
_tls-rustls-ring = ["sqlx-core/_tls-rustls-ring"]
2020

21+
_sqlite = []
22+
2123
# SQLx features
2224
derive = []
2325
macros = []
@@ -26,7 +28,8 @@ migrate = ["sqlx-core/migrate"]
2628
# database
2729
mysql = ["sqlx-mysql"]
2830
postgres = ["sqlx-postgres"]
29-
sqlite = ["sqlx-sqlite"]
31+
sqlite = ["_sqlite", "sqlx-sqlite/bundled"]
32+
sqlite-unbundled = ["_sqlite", "sqlx-sqlite/unbundled"]
3033

3134
# type integrations
3235
json = ["sqlx-core/json", "sqlx-mysql?/json", "sqlx-postgres?/json", "sqlx-sqlite?/json"]

sqlx-macros-core/src/database/impls.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ mod sqlx {
4444
#[cfg(feature = "postgres")]
4545
pub use sqlx_postgres as postgres;
4646

47-
#[cfg(feature = "sqlite")]
47+
#[cfg(feature = "_sqlite")]
4848
pub use sqlx_sqlite as sqlite;
4949
}
5050

@@ -61,7 +61,7 @@ impl_database_ext! {
6161
row: sqlx::postgres::PgRow,
6262
}
6363

64-
#[cfg(feature = "sqlite")]
64+
#[cfg(feature = "_sqlite")]
6565
impl_database_ext! {
6666
sqlx::sqlite::Sqlite,
6767
row: sqlx::sqlite::SqliteRow,

sqlx-macros-core/src/database/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use sqlx_core::describe::Describe;
1010
use sqlx_core::executor::Executor;
1111
use sqlx_core::type_checking::TypeChecking;
1212

13-
#[cfg(any(feature = "postgres", feature = "mysql", feature = "sqlite"))]
13+
#[cfg(any(feature = "postgres", feature = "mysql", feature = "_sqlite"))]
1414
mod impls;
1515

1616
pub trait DatabaseExt: Database + TypeChecking {

sqlx-macros-core/src/derives/decode.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ fn expand_derive_decode_strong_enum(
225225
));
226226
}
227227

228-
if cfg!(feature = "sqlite") {
228+
if cfg!(feature = "_sqlite") {
229229
tts.extend(quote!(
230230
#[automatically_derived]
231231
impl<'r> ::sqlx::decode::Decode<'r, ::sqlx::sqlite::Sqlite> for #ident {

sqlx-macros-core/src/derives/type.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ fn expand_derive_has_sql_type_strong_enum(
211211
}
212212
}
213213

214-
if cfg!(feature = "sqlite") {
214+
if cfg!(feature = "_sqlite") {
215215
tts.extend(quote!(
216216
#[automatically_derived]
217217
impl sqlx::Type<::sqlx::Sqlite> for #ident {

sqlx-macros-core/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub const FOSS_DRIVERS: &[QueryDriver] = &[
4747
QueryDriver::new::<sqlx_mysql::MySql>(),
4848
#[cfg(feature = "postgres")]
4949
QueryDriver::new::<sqlx_postgres::Postgres>(),
50-
#[cfg(feature = "sqlite")]
50+
#[cfg(feature = "_sqlite")]
5151
QueryDriver::new::<sqlx_sqlite::Sqlite>(),
5252
];
5353

sqlx-macros/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ migrate = ["sqlx-macros-core/migrate"]
3030
mysql = ["sqlx-macros-core/mysql"]
3131
postgres = ["sqlx-macros-core/postgres"]
3232
sqlite = ["sqlx-macros-core/sqlite"]
33+
sqlite-unbundled = ["sqlx-macros-core/sqlite-unbundled"]
3334

3435
# type
3536
bigdecimal = ["sqlx-macros-core/bigdecimal"]

sqlx-sqlite/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ uuid = ["dep:uuid", "sqlx-core/uuid"]
2323

2424
regexp = ["dep:regex"]
2525

26+
bundled = ["libsqlite3-sys/bundled"]
27+
unbundled = ["libsqlite3-sys/buildtime_bindgen"]
28+
2629
[dependencies]
2730
futures-core = { version = "0.3.19", default-features = false }
2831
futures-channel = { version = "0.3.19", default-features = false, features = ["sink", "alloc", "std"] }
@@ -55,7 +58,6 @@ default-features = false
5558
features = [
5659
"pkg-config",
5760
"vcpkg",
58-
"bundled",
5961
"unlock_notify"
6062
]
6163

sqlx-sqlite/src/lib.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
//!
33
//! ### Note: linkage is semver-exempt.
44
//! This driver uses the `libsqlite3-sys` crate which links the native library for SQLite 3.
5-
//! For portability, we enable the `bundled` feature which builds and links SQLite from source.
5+
//! With the "sqlite" feature, we enable the `bundled` feature which builds and links SQLite from
6+
//! source.
67
//!
78
//! We reserve the right to upgrade the version of `libsqlite3-sys` as necessary to pick up new
89
//! `3.x.y` versions of SQLite.
@@ -20,6 +21,18 @@
2021
//! ```
2122
//!
2223
//! and then upgrade these crates in lockstep when necessary.
24+
//!
25+
//! ### Dynamic linking
26+
//! To dynamically link to a system SQLite library, the "sqlite-unbundled" feature can be used
27+
//! instead.
28+
//!
29+
//! This allows updating SQLite independently of SQLx or using forked versions, but you must have
30+
//! SQLite installed on the system or provide a path to the library at build time (See
31+
//! [the `rusqlite` README](https://github.com/rusqlite/rusqlite?tab=readme-ov-file#notes-on-building-rusqlite-and-libsqlite3-sys)
32+
//! for details).
33+
//!
34+
//! It may result in link errors if the SQLite version is too old. Version `3.20.0` or newer is
35+
//! recommended. It can increase build time due to the use of bindgen.
2336
2437
// SQLite is a C library. All interactions require FFI which is unsafe.
2538
// All unsafe blocks should have comments pointing to SQLite docs and ensuring that we maintain

src/any/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub fn install_default_drivers() {
4141
sqlx_mysql::any::DRIVER,
4242
#[cfg(feature = "postgres")]
4343
sqlx_postgres::any::DRIVER,
44-
#[cfg(feature = "sqlite")]
44+
#[cfg(feature = "_sqlite")]
4545
sqlx_sqlite::any::DRIVER,
4646
])
4747
.expect("non-default drivers already installed")

src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ pub use sqlx_mysql::{self as mysql, MySql, MySqlConnection, MySqlExecutor, MySql
4444
#[doc(inline)]
4545
pub use sqlx_postgres::{self as postgres, PgConnection, PgExecutor, PgPool, Postgres};
4646

47-
#[cfg(feature = "sqlite")]
48-
#[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))]
47+
#[cfg(feature = "_sqlite")]
48+
#[cfg_attr(docsrs, doc(cfg(feature = "_sqlite")))]
4949
#[doc(inline)]
5050
pub use sqlx_sqlite::{self as sqlite, Sqlite, SqliteConnection, SqliteExecutor, SqlitePool};
5151

tests/ui-tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn ui_tests() {
3131
}
3232
}
3333

34-
if cfg!(feature = "sqlite") {
34+
if cfg!(feature = "_sqlite") {
3535
if dotenvy::var("DATABASE_URL").map_or(true, |v| {
3636
Path::is_relative(v.trim_start_matches("sqlite://").as_ref())
3737
}) {

0 commit comments

Comments
 (0)