diff --git a/Cargo.toml b/Cargo.toml index b7ed7ac2cb..3dc0d86036 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ members = [ "examples/sqlite/todos", "examples/sqlite/extension", "examples/sqlite/serialize", + "examples/sqlite/regexp", ] [workspace.package] @@ -160,7 +161,7 @@ mac_address = ["sqlx-core/mac_address", "sqlx-macros?/mac_address", "sqlx-postgr rust_decimal = ["sqlx-core/rust_decimal", "sqlx-macros?/rust_decimal", "sqlx-mysql?/rust_decimal", "sqlx-postgres?/rust_decimal"] time = ["sqlx-core/time", "sqlx-macros?/time", "sqlx-mysql?/time", "sqlx-postgres?/time", "sqlx-sqlite?/time"] uuid = ["sqlx-core/uuid", "sqlx-macros?/uuid", "sqlx-mysql?/uuid", "sqlx-postgres?/uuid", "sqlx-sqlite?/uuid"] -regexp = ["sqlx-sqlite?/regexp"] +regexp = ["sqlx-sqlite?/regexp", "sqlx-macros?/regexp"] bstr = ["sqlx-core/bstr"] [workspace.dependencies] diff --git a/examples/sqlite/regexp/Cargo.toml b/examples/sqlite/regexp/Cargo.toml new file mode 100644 index 0000000000..ac28e742f1 --- /dev/null +++ b/examples/sqlite/regexp/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "sqlx-example-sqlite-regexp" +version = "0.1.0" +license.workspace = true +edition.workspace = true +repository.workspace = true +keywords.workspace = true +categories.workspace = true +authors.workspace = true + +[dependencies] +sqlx = { path = "../../../", features = [ "sqlite", "runtime-tokio", "tls-native-tls", "sqlx-toml", "regexp"] } +tokio = { version = "1.25.0", features = ["rt", "macros"]} +anyhow = "1.0.58" + +[lints] +workspace = true diff --git a/examples/sqlite/regexp/build.rs b/examples/sqlite/regexp/build.rs new file mode 100644 index 0000000000..57597abdd8 --- /dev/null +++ b/examples/sqlite/regexp/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rerun-if-changed=sqlx.toml"); +} diff --git a/examples/sqlite/regexp/sqlx.toml b/examples/sqlite/regexp/sqlx.toml new file mode 100644 index 0000000000..1c11fb0f1f --- /dev/null +++ b/examples/sqlite/regexp/sqlx.toml @@ -0,0 +1,4 @@ +[drivers.sqlite] +unsafe-load-extensions = [] + +register-regexp = true \ No newline at end of file diff --git a/examples/sqlite/regexp/src/main.rs b/examples/sqlite/regexp/src/main.rs new file mode 100644 index 0000000000..273deace16 --- /dev/null +++ b/examples/sqlite/regexp/src/main.rs @@ -0,0 +1,24 @@ +use sqlx::{query, sqlite::SqliteConnectOptions, ConnectOptions}; +use std::str::FromStr; + +#[tokio::main(flavor = "current_thread")] +async fn main() -> anyhow::Result<()> { + let mut conn = SqliteConnectOptions::from_str("sqlite::memory:")? + .with_regexp() + .connect() + .await?; + + // We're not running the migrations here, for the sake of brevity + // and to confirm that the needed extension was loaded during the + // CLI migrate operation. It would not be unusual to run the + // migrations here as well, though, using the database connection + // we just configured. + + let _ = query!("SELECT 1 AS value WHERE 1 REGEXP '.*'") + .fetch_one(&mut conn) + .await?; + + println!("Queries which require the regexp function were successfully executed."); + + Ok(()) +} diff --git a/sqlx-core/src/config/drivers.rs b/sqlx-core/src/config/drivers.rs index c3416541cd..d8036d8e5c 100644 --- a/sqlx-core/src/config/drivers.rs +++ b/sqlx-core/src/config/drivers.rs @@ -103,6 +103,14 @@ pub struct SqliteConfig { /// unsafe-load-extensions = ["uuid", "vsv"] /// ``` pub unsafe_load_extensions: Vec, + + /// Specifies whether the driver should load the `REGEXP` function at build time. + /// + /// The `regexp` feature-flag must be enabled. + /// + /// # Note: Does not configure runtime regexp registering. + /// The function must be registered separately using `SqliteConnectOptions::with_regexp()`. + pub register_regexp: Option, } /// Extension for the SQLite database driver. diff --git a/sqlx-core/src/config/reference.toml b/sqlx-core/src/config/reference.toml index 618ac23c91..e8f8bcaa86 100644 --- a/sqlx-core/src/config/reference.toml +++ b/sqlx-core/src/config/reference.toml @@ -49,6 +49,13 @@ unsafe-load-extensions = [ { path = "vsv_renamed", entrypoint = "sqlite3_vsv_init" }, ] +# Automatically registers the regexp function over the sqlite database at build time if the corresponding feature flag is enabled. +# +# Must be specified separately at run-time using `SqliteConnectionOptions::with_regexp()`. +# +# Defaults to false. +register-regexp = false + # Configure external drivers in macros and sqlx-cli. # # These keys are only validated when the external driver tries to parse them, diff --git a/sqlx-macros-core/Cargo.toml b/sqlx-macros-core/Cargo.toml index 42bf0f5e8c..01c99d38d3 100644 --- a/sqlx-macros-core/Cargo.toml +++ b/sqlx-macros-core/Cargo.toml @@ -54,6 +54,8 @@ rust_decimal = ["sqlx-core/rust_decimal", "sqlx-mysql?/rust_decimal", "sqlx-post time = ["sqlx-core/time", "sqlx-mysql?/time", "sqlx-postgres?/time", "sqlx-sqlite?/time"] uuid = ["sqlx-core/uuid", "sqlx-mysql?/uuid", "sqlx-postgres?/uuid", "sqlx-sqlite?/uuid"] +regexp = ["sqlx-sqlite?/regexp"] + [dependencies] sqlx-core = { workspace = true, features = ["offline"] } sqlx-mysql = { workspace = true, features = ["offline", "migrate"], optional = true, default-features = false } diff --git a/sqlx-macros/Cargo.toml b/sqlx-macros/Cargo.toml index bd90da9608..028b5331f6 100644 --- a/sqlx-macros/Cargo.toml +++ b/sqlx-macros/Cargo.toml @@ -53,6 +53,8 @@ time = ["sqlx-macros-core/time"] uuid = ["sqlx-macros-core/uuid"] json = ["sqlx-macros-core/json"] +regexp = ["sqlx-macros-core/regexp"] + [dependencies] sqlx-core = { workspace = true, features = ["any"] } sqlx-macros-core = { workspace = true } diff --git a/sqlx-sqlite/src/options/mod.rs b/sqlx-sqlite/src/options/mod.rs index 0cafc4d08c..df018c586f 100644 --- a/sqlx-sqlite/src/options/mod.rs +++ b/sqlx-sqlite/src/options/mod.rs @@ -670,6 +670,26 @@ impl SqliteConnectOptions { )); } + #[cfg(feature = "regexp")] + if config + .register_regexp + .is_some_and(|register_regexp| register_regexp) + { + self = self.with_regexp(); + } + + #[cfg(not(feature = "regexp"))] + if config + .register_regexp + .is_some_and(|register_regexp| register_regexp) + { + return Err(sqlx_core::Error::Configuration( + "sqlx.toml sets drivers.sqlite.register-regexp to true but regexp is not enabled;\ + enable the `regexp` feature of SQLx to use sqlite regexp function" + .into(), + )); + } + Ok(self) } }