From 649b0a6ca5c8418c502b23e57a86ab86ab8a5e26 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Mon, 22 Jul 2024 17:42:54 +0200 Subject: [PATCH] Implemented a version check --- Cargo.lock | 504 ++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 1 + martin/Cargo.toml | 2 + martin/src/pg/errors.rs | 6 + martin/src/pg/pool.rs | 138 ++++++++--- 5 files changed, 605 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad307c0aa..f37bcc414 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,7 +54,7 @@ dependencies = [ "encoding_rs", "flate2", "futures-core", - "h2", + "h2 0.3.26", "http 0.2.12", "httparse", "httpdate", @@ -433,6 +433,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.3.0" @@ -589,6 +595,56 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "bollard" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aed08d3adb6ebe0eff737115056652670ae290f177759aac19c30456135f94c" +dependencies = [ + "base64 0.22.1", + "bollard-stubs", + "bytes", + "futures-core", + "futures-util", + "hex", + "home", + "http 1.1.0", + "http-body-util", + "hyper 1.4.1", + "hyper-named-pipe", + "hyper-rustls 0.26.0", + "hyper-util", + "hyperlocal-next", + "log", + "pin-project-lite", + "rustls 0.22.4", + "rustls-native-certs", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_derive", + "serde_json", + "serde_repr", + "serde_urlencoded", + "thiserror", + "tokio", + "tokio-util", + "tower-service", + "url", + "winapi", +] + +[[package]] +name = "bollard-stubs" +version = "1.44.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709d9aa1c37abb89d40f19f5d0ad6f0d88cb1581264e571c9350fc5bb89cf1c5" +dependencies = [ + "serde", + "serde_repr", + "serde_with", +] + [[package]] name = "brotli" version = "3.5.0" @@ -1099,6 +1155,12 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "data-url" version = "0.3.1" @@ -1200,6 +1262,38 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31951f49556e34d90ed28342e1df7e1cb7a229c4cab0aecc627b5d91edd41d07" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -1236,6 +1330,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-as-inner" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "enum-display" version = "0.1.4" @@ -1451,7 +1557,7 @@ dependencies = [ "enum_dispatch", "fs4", "memmapix", - "parse-display", + "parse-display 0.8.2", "pin-project-lite", "tokio", ] @@ -1719,6 +1825,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "h2" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.2.6", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.4.1" @@ -1781,6 +1906,51 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "hilbert_2d" version = "1.1.0" @@ -1814,6 +1984,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.12" @@ -1920,6 +2101,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", + "h2 0.4.5", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -1930,6 +2112,40 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-named-pipe" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" +dependencies = [ + "hex", + "hyper 1.4.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", + "winapi", +] + +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "log", + "rustls 0.22.4", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.25.0", + "tower-service", +] + [[package]] name = "hyper-rustls" version = "0.27.2" @@ -1940,12 +2156,13 @@ dependencies = [ "http 1.1.0", "hyper 1.4.1", "hyper-util", - "rustls", + "rustls 0.23.11", "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tower-service", + "webpki-roots", ] [[package]] @@ -1968,6 +2185,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "hyperlocal-next" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf569d43fa9848e510358c07b80f4adf34084ddc28c6a4a651ee8474c070dcc" +dependencies = [ + "hex", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -1997,6 +2229,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -2074,6 +2316,18 @@ dependencies = [ "toml", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg 0.50.0", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -2296,6 +2550,16 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + [[package]] name = "libsqlite3-sys" version = "0.27.0" @@ -2358,15 +2622,25 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "martin" -version = "0.14.2" +version = "0.15.0" dependencies = [ "actix-cors", "actix-http", "actix-rt", "actix-web", "actix-web-static-files", + "anyhow", "async-trait", "bit-set", "brotli 6.0.0", @@ -2396,7 +2670,7 @@ dependencies = [ "pprof", "regex", "rstest", - "rustls", + "rustls 0.23.11", "rustls-native-certs", "rustls-pemfile", "semver", @@ -2407,6 +2681,7 @@ dependencies = [ "spreet", "static-files", "subst", + "testcontainers-modules", "thiserror", "tilejson", "tokio", @@ -2424,6 +2699,12 @@ dependencies = [ "insta", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "mbtiles" version = "0.11.1" @@ -2754,6 +3035,12 @@ 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.1" @@ -2811,10 +3098,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6509d08722b53e8dafe97f2027b22ccbe3a5db83cb352931e9716b0aa44bc5c" dependencies = [ "once_cell", - "parse-display-derive", + "parse-display-derive 0.8.2", "regex", ] +[[package]] +name = "parse-display" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914a1c2265c98e2446911282c6ac86d8524f495792c38c5bd884f80499c7538a" +dependencies = [ + "parse-display-derive 0.9.1", + "regex", + "regex-syntax 0.8.4", +] + [[package]] name = "parse-display-derive" version = "0.8.2" @@ -2826,7 +3124,21 @@ dependencies = [ "quote", "regex", "regex-syntax 0.7.5", - "structmeta", + "structmeta 0.2.0", + "syn 2.0.71", +] + +[[package]] +name = "parse-display-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae7800a4c974efd12df917266338e79a7a74415173caf7e70aa0a0707345281" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "regex-syntax 0.8.4", + "structmeta 0.3.0", "syn 2.0.71", ] @@ -3281,6 +3593,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quick-xml" version = "0.26.0" @@ -3301,7 +3619,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls", + "rustls 0.23.11", "thiserror", "tokio", "tracing", @@ -3317,7 +3635,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls", + "rustls 0.23.11", "slab", "thiserror", "tinyvec", @@ -3435,6 +3753,17 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "regex" version = "1.10.5" @@ -3490,13 +3819,16 @@ checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "base64 0.22.1", "bytes", + "encoding_rs", "futures-core", "futures-util", + "h2 0.4.5", + "hickory-resolver", "http 1.1.0", "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls", + "hyper-rustls 0.27.2", "hyper-util", "ipnet", "js-sys", @@ -3506,7 +3838,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls", + "rustls 0.23.11", "rustls-native-certs", "rustls-pemfile", "rustls-pki-types", @@ -3515,13 +3847,24 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", + "webpki-roots", + "winreg 0.52.0", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", ] [[package]] @@ -3684,6 +4027,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + [[package]] name = "rustls" version = "0.23.11" @@ -3857,6 +4214,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "serde_tuple" version = "0.5.0" @@ -4370,7 +4738,19 @@ checksum = "78ad9e09554f0456d67a69c1584c9798ba733a5b50349a6c0d0948710523922d" dependencies = [ "proc-macro2", "quote", - "structmeta-derive", + "structmeta-derive 0.2.0", + "syn 2.0.71", +] + +[[package]] +name = "structmeta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" +dependencies = [ + "proc-macro2", + "quote", + "structmeta-derive 0.3.0", "syn 2.0.71", ] @@ -4385,6 +4765,17 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "structmeta-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "subst" version = "0.3.3" @@ -4488,6 +4879,44 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "testcontainers" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cbe485aafddfd8b2d01665937c95498d894c07fabd9c4e06a53c7da4ccc56" +dependencies = [ + "async-trait", + "bollard", + "bollard-stubs", + "bytes", + "dirs", + "docker_credential", + "either", + "futures", + "log", + "memchr", + "parse-display 0.9.1", + "pin-project-lite", + "reqwest", + "serde", + "serde_json", + "serde_with", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "url", +] + +[[package]] +name = "testcontainers-modules" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a433ba83c79b59254a8a712c2c435750272574ddbc57091b69724d2696dc57d" +dependencies = [ + "testcontainers", +] + [[package]] name = "thiserror" version = "1.0.62" @@ -4665,20 +5094,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04fb792ccd6bbcd4bba408eb8a292f70fc4a3589e5d793626f45190e6454b6ab" dependencies = [ "ring", - "rustls", + "rustls 0.23.11", "tokio", "tokio-postgres", - "tokio-rustls", + "tokio-rustls 0.26.0", "x509-certificate", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls", + "rustls 0.23.11", "rustls-pki-types", "tokio", ] @@ -4914,8 +5354,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", + "serde", ] [[package]] @@ -5125,6 +5566,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "weezl" version = "0.1.8" @@ -5154,6 +5604,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -5342,6 +5798,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "winreg" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index b1b112946..3300ff907 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,7 @@ pretty_assertions = "1" regex = "1" rstest = "0.21" rustls = "0.23.11" +testcontainers-modules = { version = "0.8.0", features = ["postgres"] } # ring feature does not require NASM windows executable, but works slower #rustls = { version = "0.23", default-features = false, features = ["logging", "std", "tls12", "ring"] } rustls-native-certs = "0.7" diff --git a/martin/Cargo.toml b/martin/Cargo.toml index 7d9196052..55698a58d 100644 --- a/martin/Cargo.toml +++ b/martin/Cargo.toml @@ -125,3 +125,5 @@ indoc.workspace = true insta = { workspace = true, features = ["yaml"] } pprof.workspace = true rstest.workspace = true +anyhow.workspace = true +testcontainers-modules.workspace = true diff --git a/martin/src/pg/errors.rs b/martin/src/pg/errors.rs index 37cd6e7c0..7bcc21aff 100644 --- a/martin/src/pg/errors.rs +++ b/martin/src/pg/errors.rs @@ -49,9 +49,15 @@ pub enum PgError { #[error("Unable to parse PostGIS version {1}: {0}")] BadPostgisVersion(#[source] semver::Error, String), + #[error("Unable to parse PostgreSQL version {1}: {0}")] + BadPostgresVersion(#[source] semver::Error, String), + #[error("PostGIS version {0} is too old, minimum required is {1}")] PostgisTooOld(Version, Version), + #[error("PostgreSQL version {0} is too old, minimum required is {1}")] + PostgresqlTooOld(Version, Version), + #[error("Invalid extent setting in source {0} for table {1}: extent=0")] InvalidTableExtent(String, String), diff --git a/martin/src/pg/pool.rs b/martin/src/pg/pool.rs index 6fb3c7103..dd266659f 100755 --- a/martin/src/pg/pool.rs +++ b/martin/src/pg/pool.rs @@ -6,17 +6,22 @@ use semver::Version; use crate::pg::config::PgConfig; use crate::pg::tls::{make_connector, parse_conn_str, SslModeOverride}; use crate::pg::PgError::{ - BadPostgisVersion, PostgisTooOld, PostgresError, PostgresPoolBuildError, PostgresPoolConnError, + BadPostgisVersion, BadPostgresVersion, PostgisTooOld, PostgresError, PostgresPoolBuildError, + PostgresPoolConnError, PostgresqlTooOld, }; use crate::pg::PgResult; pub const POOL_SIZE_DEFAULT: usize = 20; -// We require ST_TileEnvelope that was added in PostGIS 3.0.0 -// See https://postgis.net/docs/ST_TileEnvelope.html +/// We require `ST_TileEnvelope` that was added in [`PostGIS 3.0.0`](https://postgis.net/2019/10/PostGIS-3.0.0/) +/// See const MINIMUM_POSTGIS_VER: Version = Version::new(3, 0, 0); -// After this version we can use margin parameter in ST_TileEnvelope +/// Minimum version of postgres required for [`MINIMUM_POSTGIS_VER`] according to the [Support Matrix](https://trac.osgeo.org/postgis/wiki/UsersWikiPostgreSQLPostGIS) +const MINIMUM_POSTGRES_VER: Version = Version::new(11, 0, 0); +/// After this [`PostGIS`](https://postgis.net/) version we can use margin parameter in `ST_TileEnvelope` const RECOMMENDED_POSTGIS_VER: Version = Version::new(3, 1, 0); +/// Minimum version of postgres required for [`RECOMMENDED_POSTGIS_VER`] according to the [Support Matrix](https://trac.osgeo.org/postgis/wiki/UsersWikiPostgreSQLPostGIS) +const RECOMMENDED_POSTGRES_VER: Version = Version::new(12, 0, 0); #[derive(Clone, Debug)] pub struct PgPool { @@ -35,32 +40,23 @@ impl PgPool { .build() .map_err(|e| PostgresPoolBuildError(e, id.clone()))?; - let version: String = get_conn(&pool, id.as_str()) - .await? - .query_one( - r" -SELECT - (regexp_matches( - PostGIS_Lib_Version(), - '^(\d+\.\d+\.\d+)', - 'g' - ))[1] as version; - ", - &[], - ) - .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))?; - if version < MINIMUM_POSTGIS_VER { - return Err(PostgisTooOld(version, MINIMUM_POSTGIS_VER)); + let postgres_version = get_postgres_version(&pool, &id).await?; + if postgres_version < MINIMUM_POSTGRES_VER { + return Err(PostgresqlTooOld(postgres_version, MINIMUM_POSTGRES_VER)); } - if version < RECOMMENDED_POSTGIS_VER { - warn!("PostGIS {version} is before the recommended {RECOMMENDED_POSTGIS_VER}. Margin parameter in ST_TileEnvelope is not supported, so tiles may be cut off at the edges."); + if postgres_version < RECOMMENDED_POSTGRES_VER { + warn!("PostgreSQL {postgres_version} is before the recommended minimum of {RECOMMENDED_POSTGRES_VER}."); } - let margin = version >= RECOMMENDED_POSTGIS_VER; + let postgis_version = get_postgis_version(&pool, &id).await?; + if postgis_version < MINIMUM_POSTGIS_VER { + return Err(PostgisTooOld(postgis_version, 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_version >= RECOMMENDED_POSTGIS_VER; Ok(Self { id, pool, margin }) } @@ -115,8 +111,96 @@ SELECT } } +/// 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; + ", + &[], + ) + .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) +} + +/// 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? + .query_one( + r" +SELECT + (regexp_matches( + current_setting('server_version'), + '^(\d+\.\d+)', + 'g' + ))[1] || '.0' as version; + ", + &[], + ) + .await + .map(|row| row.get("version")) + .map_err(|e| PostgresError(e, "querying postgres version"))?; + + let version: Version = version + .parse() + .map_err(|e| BadPostgresVersion(e, version))?; + Ok(version) +} + async fn get_conn(pool: &Pool, id: &str) -> PgResult { pool.get() .await .map_err(|e| PostgresPoolConnError(e, id.to_string())) } + +#[cfg(test)] +mod tests { + use super::*; + 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; + + #[tokio::test] + async fn parse_version() -> anyhow::Result<()> { + let node = Postgres::default() + .with_name("postgis/postgis") + .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?) + .dbname("postgres") + .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?; + 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?; + 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(()) + } +}