diff --git a/Cargo.lock b/Cargo.lock index 3cbe3db18..4c796d477 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -652,6 +652,17 @@ dependencies = [ "brotli-decompressor 4.0.1", ] +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor 4.0.1", +] + [[package]] name = "brotli-decompressor" version = "2.5.1" @@ -1254,27 +1265,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - [[package]] name = "docker_credential" version = "1.3.1" @@ -2434,7 +2424,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall", + "redox_syscall 0.5.7", ] [[package]] @@ -2511,7 +2501,7 @@ dependencies = [ "anyhow", "async-trait", "bit-set", - "brotli 6.0.0", + "brotli 7.0.0", "cargo-husky", "clap", "criterion", @@ -2562,7 +2552,7 @@ name = "martin-tile-utils" version = "0.5.1" dependencies = [ "approx", - "brotli 6.0.0", + "brotli 7.0.0", "flate2", "insta", ] @@ -2898,12 +2888,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - [[package]] name = "oxipng" version = "9.1.2" @@ -2949,7 +2933,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.7", "smallvec", "windows-targets 0.52.6", ] @@ -3595,22 +3579,20 @@ checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f" [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags 2.6.0", + "bitflags 1.3.2", ] [[package]] -name = "redox_users" -version = "0.4.6" +name = "redox_syscall" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "getrandom", - "libredox", - "thiserror", + "bitflags 2.6.0", ] [[package]] @@ -4725,17 +4707,17 @@ dependencies = [ [[package]] name = "testcontainers" -version = "0.21.1" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7d80fe0008971413157e67062150cbf508b92f0eb525b9f49de1aec4267f24" +checksum = "5f40cc2bd72e17f328faf8ca7687fe337e61bccd8acf9674fa78dd3792b045e1" dependencies = [ "async-trait", "bollard", "bollard-stubs", "bytes", - "dirs", "docker_credential", "either", + "etcetera", "futures", "log", "memchr", @@ -4747,15 +4729,16 @@ dependencies = [ "thiserror", "tokio", "tokio-stream", + "tokio-tar", "tokio-util", "url", ] [[package]] name = "testcontainers-modules" -version = "0.9.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "868e8e818fe37b8ed4c21ac72185206b48e8767b5ad3836d7ec0e5c9386e19a2" +checksum = "708fce58200e480633a428b7356fc39eb7fef02e47bd6faa94ba1d0746e6f17e" dependencies = [ "testcontainers", ] @@ -4987,6 +4970,21 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tar" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5714c010ca3e5c27114c1cdeb9d14641ace49874aa5626d7149e47aedace75" +dependencies = [ + "filetime", + "futures-core", + "libc", + "redox_syscall 0.3.5", + "tokio", + "tokio-stream", + "xattr", +] + [[package]] name = "tokio-util" version = "0.7.12" @@ -5440,7 +5438,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall", + "redox_syscall 0.5.7", "wasite", "web-sys", ] @@ -5693,6 +5691,17 @@ dependencies = [ "tls_codec", ] +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + [[package]] name = "xmlparser" version = "0.13.6" diff --git a/Cargo.toml b/Cargo.toml index 3dd1d3eb1..27b11a0c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ anyhow = "1.0" approx = "0.5.1" async-trait = "0.1" bit-set = "0.8" -brotli = ">=5, <7" +brotli = ">=5, <8" cargo-husky = { version = "1", features = ["user-hooks"], default-features = false } clap = { version = "4", features = ["derive"] } criterion = { version = "0.5", features = ["async_futures", "async_tokio", "html_reports"] } @@ -83,7 +83,7 @@ sqlite-hashes = { version = "0.7.6", default-features = false, features = ["md5" sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio"] } static-files = "0.2" subst = { version = "0.3", features = ["yaml"] } -testcontainers-modules = { version = "0.9.0", features = ["postgres"] } +testcontainers-modules = { version = "0.11.3", features = ["postgres"] } thiserror = "1" tile-grid = "0.6" tilejson = "0.4" diff --git a/martin/src/pg/pool.rs b/martin/src/pg/pool.rs index 46cde969f..efa7d3ec2 100755 --- a/martin/src/pg/pool.rs +++ b/martin/src/pg/pool.rs @@ -40,23 +40,26 @@ impl PgPool { .build() .map_err(|e| PostgresPoolBuildError(e, id.clone()))?; - let postgres_version = get_postgres_version(&pool, &id).await?; - if postgres_version < MINIMUM_POSTGRES_VER { - return Err(PostgresqlTooOld(postgres_version, MINIMUM_POSTGRES_VER)); + let conn = get_conn(&pool, &id).await?; + let pg_ver = get_postgres_version(&conn).await?; + if pg_ver < MINIMUM_POSTGRES_VER { + return Err(PostgresqlTooOld(pg_ver, MINIMUM_POSTGRES_VER)); } - if postgres_version < RECOMMENDED_POSTGRES_VER { - warn!("PostgreSQL {postgres_version} is before the recommended minimum of {RECOMMENDED_POSTGRES_VER}."); + if pg_ver < RECOMMENDED_POSTGRES_VER { + warn!("PostgreSQL {pg_ver} is older than the recommended {RECOMMENDED_POSTGRES_VER}."); } - let postgis_version = get_postgis_version(&pool, &id).await?; - if postgis_version < MINIMUM_POSTGIS_VER { - return Err(PostgisTooOld(postgis_version, MINIMUM_POSTGIS_VER)); + let postgis_ver = get_postgis_version(&conn).await?; + if postgis_ver < MINIMUM_POSTGIS_VER { + return Err(PostgisTooOld(postgis_ver, MINIMUM_POSTGIS_VER)); } - if postgis_version < RECOMMENDED_POSTGIS_VER { - warn!("PostGIS {postgis_version} is before the recommended minimum of {RECOMMENDED_POSTGIS_VER}. Margin parameter in ST_TileEnvelope is not supported, so tiles may be cut off at the edges."); + let margin = postgis_ver >= RECOMMENDED_POSTGIS_VER; + if !margin { + warn!("PostGIS {postgis_ver} is older than the recommended {RECOMMENDED_POSTGIS_VER}. Margin parameter in ST_TileEnvelope is not supported, so tiles may be cut off at the edges."); } - let margin = postgis_version >= RECOMMENDED_POSTGIS_VER; + info!("Connected to PostgreSQL {pg_ver} / PostGIS {postgis_ver} for source {id}"); + Ok(Self { id, pool, margin }) } @@ -111,42 +114,23 @@ impl PgPool { } } -/// parses the [postgis version](https://postgis.net/docs/PostGIS_Lib_Version.html) -async fn get_postgis_version(pool: &Pool, id: &str) -> PgResult { - let version: String = get_conn(pool, id) - .await? - .query_one( - r" - SELECT - (regexp_matches( - PostGIS_Lib_Version(), - '^(\d+\.\d+\.\d+)', - 'g' - ))[1] as version; - ", - &[], - ) +async fn get_conn(pool: &Pool, id: &str) -> PgResult { + pool.get() .await - .map(|row| row.get("version")) - .map_err(|e| PostgresError(e, "querying postgis version"))?; - let version: Version = version.parse().map_err(|e| BadPostgisVersion(e, version))?; - Ok(version) + .map_err(|e| PostgresPoolConnError(e, id.to_string())) } -/// parses the [postgres version](https://www.postgresql.org/support/versioning/) -/// Postgres does have Major.Minor versioning natively, so we "halucinate" a .Patch -async fn get_postgres_version(pool: &Pool, id: &str) -> PgResult { - let version: String = get_conn(pool, id) - .await? +/// Get [PostgreSQL version](https://www.postgresql.org/support/versioning/). +/// `PostgreSQL` only has a Major.Minor versioning, so we use 0 the patch version +async fn get_postgres_version(conn: &Object) -> PgResult { + let version: String = conn .query_one( r" -SELECT - (regexp_matches( +SELECT (regexp_matches( current_setting('server_version'), '^(\d+\.\d+)', 'g' - ))[1] || '.0' as version; - ", + ))[1] || '.0' as version;", &[], ) .await @@ -156,13 +140,29 @@ SELECT let version: Version = version .parse() .map_err(|e| BadPostgresVersion(e, version))?; + Ok(version) } -async fn get_conn(pool: &Pool, id: &str) -> PgResult { - pool.get() +/// Get [PostGIS version](https://postgis.net/docs/PostGIS_Lib_Version.html) +async fn get_postgis_version(conn: &Object) -> PgResult { + let version: String = conn + .query_one( + r" +SELECT (regexp_matches( + PostGIS_Lib_Version(), + '^(\d+\.\d+\.\d+)', + 'g' + ))[1] as version;", + &[], + ) .await - .map_err(|e| PostgresPoolConnError(e, id.to_string())) + .map(|row| row.get("version")) + .map_err(|e| PostgresError(e, "querying postgis version"))?; + + let version: Version = version.parse().map_err(|e| BadPostgisVersion(e, version))?; + + Ok(version) } #[cfg(test)] @@ -171,8 +171,8 @@ mod tests { use deadpool_postgres::tokio_postgres::Config; use postgres::NoTls; use testcontainers_modules::postgres::Postgres; - use testcontainers_modules::testcontainers::runners::AsyncRunner; - use testcontainers_modules::testcontainers::ImageExt; + use testcontainers_modules::testcontainers::runners::AsyncRunner as _; + use testcontainers_modules::testcontainers::ImageExt as _; #[tokio::test] async fn parse_version() -> anyhow::Result<()> { @@ -181,6 +181,7 @@ mod tests { .with_tag("11-3.0") // purposely very old and stable .start() .await?; + let pg_config = Config::new() .host(node.get_host().await?.to_string()) .port(node.get_host_port_ipv4(5432).await?) @@ -188,19 +189,25 @@ mod tests { .user("postgres") .password("postgres") .to_owned(); + let mgr_config = ManagerConfig { recycling_method: RecyclingMethod::Fast, }; + let mgr = Manager::from_config(pg_config, NoTls, mgr_config); - let pool = Pool::builder(mgr).max_size(2).build().unwrap(); - let pg_version = get_postgres_version(&pool, "test").await?; + let pool = Pool::builder(mgr).max_size(2).build()?; + let conn = pool.get().await?; + + let pg_version = get_postgres_version(&conn).await?; assert_eq!(pg_version.major, 11); assert!(pg_version.minor >= 10); // we don't want to break this testcase just because postgis updates that image assert_eq!(pg_version.patch, 0); - let postgis_version = get_postgis_version(&pool, "test").await?; + + let postgis_version = get_postgis_version(&conn).await?; assert_eq!(postgis_version.major, 3); assert_eq!(postgis_version.minor, 0); assert!(postgis_version.patch >= 3); // we don't want to break this testcase just because postgis updates that image + Ok(()) } } diff --git a/martin/src/pg/query_tables.rs b/martin/src/pg/query_tables.rs index 23a13c15a..9aea4d575 100644 --- a/martin/src/pg/query_tables.rs +++ b/martin/src/pg/query_tables.rs @@ -24,8 +24,9 @@ static DEFAULT_CLIP_GEOM: bool = true; /// Examine a database to get a list of all tables that have geometry columns. pub async fn query_available_tables(pool: &PgPool) -> PgResult { - let conn = pool.get().await?; - let rows = conn + let rows = pool + .get() + .await? .query(include_str!("scripts/query_available_tables.sql"), &[]) .await .map_err(|e| PostgresError(e, "querying available tables"))?;