From 91e709ed49fcb99742964920377786d907fea540 Mon Sep 17 00:00:00 2001 From: Ethan Hardy Date: Wed, 6 Mar 2024 16:51:43 -0600 Subject: [PATCH 1/9] cargo.lock --- Cargo.lock | 485 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 478 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b28847e..9a011e36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,6 +66,161 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" +dependencies = [ + "concurrent-queue", + "event-listener 5.2.0", + "event-listener-strategy 0.5.0", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" +dependencies = [ + "async-lock 3.3.0", + "async-task", + "concurrent-queue", + "fastrand 2.0.1", + "futures-lite 2.2.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.2.0", + "async-executor", + "async-io 2.3.1", + "async-lock 3.3.0", + "blocking", + "futures-lite 2.2.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2 0.4.10", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +dependencies = [ + "async-lock 3.3.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.2.0", + "parking", + "polling 3.5.0", + "rustix 0.38.31", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener 4.0.3", + "event-listener-strategy 0.4.0", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel 1.9.0", + "async-global-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" + [[package]] name = "async-trait" version = "0.1.77" @@ -77,6 +232,12 @@ dependencies = [ "syn 2.0.49", ] +[[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.1.0" @@ -158,6 +319,22 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +dependencies = [ + "async-channel 2.2.0", + "async-lock 3.3.0", + "async-task", + "fastrand 2.0.1", + "futures-io", + "futures-lite 2.2.0", + "piper", + "tracing", +] + [[package]] name = "bson" version = "2.9.0" @@ -231,6 +408,15 @@ dependencies = [ "windows-targets 0.52.0", ] +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-random" version = "0.1.17" @@ -288,6 +474,12 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crunchy" version = "0.2.2" @@ -431,7 +623,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -467,6 +659,64 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +dependencies = [ + "event-listener 5.2.0", + "pin-project-lite", +] + [[package]] name = "fancy-regex" version = "0.11.0" @@ -477,6 +727,21 @@ dependencies = [ "regex", ] +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "finl_unicode" version = "1.2.0" @@ -551,6 +816,34 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +dependencies = [ + "fastrand 2.0.1", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -617,6 +910,18 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -743,6 +1048,15 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "integration_test" version = "0.0.0" @@ -764,6 +1078,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "ipconfig" version = "0.3.2" @@ -772,7 +1097,7 @@ checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ "socket2 0.5.5", "widestring", - "windows-sys", + "windows-sys 0.48.0", "winreg", ] @@ -806,6 +1131,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -851,6 +1185,18 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + [[package]] name = "lock_api" version = "0.4.11" @@ -868,6 +1214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" dependencies = [ "serde", + "value-bag", ] [[package]] @@ -980,7 +1327,7 @@ checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1011,6 +1358,7 @@ dependencies = [ name = "mongo-odbc-driver" version = "0.0.0" dependencies = [ + "async-std", "bson", "chrono", "constants", @@ -1193,6 +1541,12 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1254,6 +1608,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.1", + "futures-io", +] + [[package]] name = "plotters" version = "0.3.5" @@ -1272,6 +1637,36 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.31", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1423,7 +1818,7 @@ dependencies = [ "libc", "spin", "untrusted", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1479,6 +1874,33 @@ dependencies = [ "semver 0.9.0", ] +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", +] + [[package]] name = "rustls" version = "0.21.10" @@ -1750,7 +2172,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1926,7 +2348,7 @@ dependencies = [ "signal-hook-registry", "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2007,6 +2429,22 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + [[package]] name = "trust-dns-proto" version = "0.21.2" @@ -2153,12 +2591,24 @@ dependencies = [ "serde", ] +[[package]] +name = "value-bag" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126e423afe2dd9ac52142e7e9d5ce4135d7e13776c529d27fd6bc49f19e3280b" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2190,6 +2640,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.91" @@ -2311,6 +2773,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -2498,7 +2969,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] From 52be409a03589324e1401501925b1e3c86ced764 Mon Sep 17 00:00:00 2001 From: EthanHardyMongo <107422381+EthanHardyMongo@users.noreply.github.com> Date: Mon, 7 Oct 2024 17:06:09 -0400 Subject: [PATCH 2/9] SQL-2374: Implement columns metadata logic for Direct cluster (#245) * cargo.lock * handle enterprise mode in get_next_metadata() --- constants/src/lib.rs | 1 + core/src/col_metadata.rs | 14 ++++++-- core/src/err.rs | 2 +- core/src/fields.rs | 77 +++++++++++++++++++++++++++++++--------- core/src/query.rs | 3 +- 5 files changed, 77 insertions(+), 20 deletions(-) diff --git a/constants/src/lib.rs b/constants/src/lib.rs index 0b29e25a..c85c2417 100644 --- a/constants/src/lib.rs +++ b/constants/src/lib.rs @@ -5,6 +5,7 @@ pub const DRIVER_NAME: &str = "MongoDB Atlas SQL ODBC Driver"; pub const DBMS_NAME: &str = "MongoDB Atlas"; pub const ODBC_VERSION: &str = "03.80"; pub const DRIVER_SHORT_NAME: &str = "mongodb-odbc"; +pub const SQL_SCHEMAS_COLLECTION: &str = "__sql_schemas"; lazy_static! { pub static ref DRIVER_METRICS_VERSION: String = format!( diff --git a/core/src/col_metadata.rs b/core/src/col_metadata.rs index d1c71221..a7a5ef04 100644 --- a/core/src/col_metadata.rs +++ b/core/src/col_metadata.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use crate::{ json_schema::{ simplified::{Atomic, ObjectSchema, Schema}, @@ -7,9 +5,11 @@ use crate::{ }, BsonTypeInfo, Error, Result, TypeMode, }; +use bson::{Bson, Document}; use definitions::{Nullability, SqlCode, SqlDataType}; use itertools::Itertools; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; // Metadata information for a column of the result set. // The information is to be used when reporting columns information from @@ -174,9 +174,19 @@ pub struct VersionedJsonSchema { #[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Default)] pub struct ResultSetSchema { pub schema: crate::json_schema::Schema, + #[serde(skip_serializing_if = "Option::is_none")] pub select_order: Option>>, } +impl ResultSetSchema { + pub fn from_sql_schemas_document(doc: &Document) -> bson::de::Result { + let as_bson = Bson::Document(doc.clone()); + let deserializer = bson::Deserializer::new(as_bson); + let deserializer = serde_stacker::Deserializer::new(deserializer); + Deserialize::deserialize(deserializer) + } +} + impl From for ResultSetSchema { fn from(sql_get_schema_response: SqlGetSchemaResponse) -> Self { Self { diff --git a/core/src/err.rs b/core/src/err.rs index 0310f180..1bf3f045 100644 --- a/core/src/err.rs +++ b/core/src/err.rs @@ -58,7 +58,7 @@ pub enum Error { "The ODBC driver version `{0}` is incompatible with libmongosqltranslate version `{1}`" )] LibmongosqltranslateLibraryIsIncompatible(&'static str, String), - #[error("The following collections were not found in the `__sql_schemas` collection: {0:?}")] + #[error("The following collection(s) were not found in the `__sql_schemas` collection: {0:?}")] SchemaDocumentNotFoundInSchemaCollection(Vec), #[error( "The libmongosqltranslate command `{0}` failed. Error message: `{1}`. Error is internal: {2}" diff --git a/core/src/fields.rs b/core/src/fields.rs index aa6159cc..49a09a17 100644 --- a/core/src/fields.rs +++ b/core/src/fields.rs @@ -1,4 +1,5 @@ use crate::{ + cluster_type::MongoClusterType, col_metadata::{MongoColMetadata, ResultSetSchema, SqlGetSchemaResponse}, collections::MongoODBCCollectionSpecification, conn::MongoConnection, @@ -7,9 +8,10 @@ use crate::{ util::to_name_regex, BsonTypeInfo, TypeMode, }; +use constants::SQL_SCHEMAS_COLLECTION; use definitions::{Nullability, SqlDataType}; use mongodb::{ - bson::{doc, Bson}, + bson::{doc, Bson, Document}, results::CollectionType, }; use once_cell::sync::OnceCell; @@ -542,23 +544,66 @@ impl MongoFields { // The collection does not match the filter, moving to the next one continue; } - let get_schema_cmd = doc! {"sqlGetSchema": collection_name.clone()}; let db = mongo_connection.client.database(&self.current_db_name); - let current_col_metadata_response: Result = - mongodb::bson::from_document( - db.run_command(get_schema_cmd).await.unwrap(), - ) - .map_err(|e| { - Error::CollectionDeserialization(collection_name.clone(), e) - }); - if let Err(error) = current_col_metadata_response { - // If there is an Error while deserializing the schema, we won't show any columns for it - warnings.push(error); - continue; - } - let current_col_metadata_response: ResultSetSchema = - current_col_metadata_response.unwrap().into(); + + let current_col_metadata_response: ResultSetSchema = if mongo_connection + .cluster_type + == MongoClusterType::AtlasDataFederation + { + let get_schema_cmd = doc! {"sqlGetSchema": &collection_name}; + + let sql_get_schema_response: Result = + mongodb::bson::from_document( + db.run_command(get_schema_cmd).await.unwrap(), + ) + .map_err(|e| { + Error::CollectionDeserialization(collection_name.clone(), e) + }); + + if let Err(error) = sql_get_schema_response { + // If there is an Error while deserializing the schema, we won't show any columns for it + warnings.push(error); + continue; + } + + sql_get_schema_response.unwrap().into() + } else if mongo_connection.cluster_type == MongoClusterType::Enterprise { + let schema_collection = + db.collection::(SQL_SCHEMAS_COLLECTION); + + let schema_doc: Document = mongo_connection + .runtime + .block_on(async { + schema_collection + .find_one(doc! { + "_id": &collection_name + }) + .await + .map_err(Error::QueryExecutionFailed) + })? + .ok_or(Error::SchemaDocumentNotFoundInSchemaCollection(vec![ + collection_name.clone(), + ]))?; + + let result_set_schema: Result = + ResultSetSchema::from_sql_schemas_document(&schema_doc).map_err( + |e| { + Error::CollectionDeserialization(collection_name.clone(), e) + }, + ); + + if let Err(error) = result_set_schema { + // If there is an Error while deserializing the schema, we won't show any columns for it + warnings.push(error); + continue; + } + + result_set_schema.unwrap() + } else { + unreachable!() + }; + match current_col_metadata_response.process_collection_metadata( &self.current_db_name, collection_name.as_str(), diff --git a/core/src/query.rs b/core/src/query.rs index bf33efe7..d522f38c 100644 --- a/core/src/query.rs +++ b/core/src/query.rs @@ -10,6 +10,7 @@ use crate::{ stmt::MongoStatement, Error, TypeMode, }; +use constants::SQL_SCHEMAS_COLLECTION; use futures::TryStreamExt; use mongodb::{ bson::{doc, document::ValueAccessError, Bson, Document}, @@ -59,7 +60,7 @@ impl MongoQuery { client: &MongoConnection, db: &Database, ) -> Result { - let schema_collection = db.collection::("__sql_schemas"); + let schema_collection = db.collection::(SQL_SCHEMAS_COLLECTION); let collection_names = namespaces .iter() From e7e8234266be12ff12c178ad452513e1b6b0a6cc Mon Sep 17 00:00:00 2001 From: Ethan Hardy Date: Mon, 14 Oct 2024 16:38:28 -0400 Subject: [PATCH 3/9] create mongosqltranslate tests and fix logic --- Cargo.lock | 2 +- constants/Cargo.toml | 2 +- core/src/col_metadata.rs | 1 + core/src/collections.rs | 8 +- core/src/conn.rs | 8 +- core/src/databases.rs | 8 +- core/src/fields.rs | 8 +- core/src/mongosqltranslate.rs | 29 ++- core/src/query.rs | 171 ++++++++++-------- core/src/util/test_connection.rs | 1 - evergreen.yml | 111 +++++++----- integration_test/tests/bind_cols_tests.rs | 4 +- integration_test/tests/cluster_type_test.rs | 16 +- integration_test/tests/common/mod.rs | 13 +- integration_test/tests/connection_tests.rs | 15 +- .../tests/free_and_cancel_tests.rs | 4 +- integration_test/tests/get_data_tests.rs | 2 +- .../tests/mongosqltranslate_tests.rs | 158 ++++++++++++++++ integration_test/tests/odbc_2_tests.rs | 4 +- .../tests/prepared_statement_tests.rs | 10 +- 20 files changed, 401 insertions(+), 174 deletions(-) create mode 100644 integration_test/tests/mongosqltranslate_tests.rs diff --git a/Cargo.lock b/Cargo.lock index 0cf4f67c..777f2051 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -571,7 +571,7 @@ dependencies = [ [[package]] name = "constants" -version = "0.0.0" +version = "2.0.0" dependencies = [ "anyhow", "cargo_toml", diff --git a/constants/Cargo.toml b/constants/Cargo.toml index 2c8af76e..8ebdfb21 100644 --- a/constants/Cargo.toml +++ b/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "constants" -version = "0.0.0" +version = "2.0.0" authors = [ "Ryan Chipman ", "Natacha Bagnard ", diff --git a/core/src/col_metadata.rs b/core/src/col_metadata.rs index a7a5ef04..4fdbfa4c 100644 --- a/core/src/col_metadata.rs +++ b/core/src/col_metadata.rs @@ -173,6 +173,7 @@ pub struct VersionedJsonSchema { // Struct representing the ResultSetSchema. #[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Default)] pub struct ResultSetSchema { + #[serde(rename = "result_set_schema")] pub schema: crate::json_schema::Schema, #[serde(skip_serializing_if = "Option::is_none")] pub select_order: Option>>, diff --git a/core/src/collections.rs b/core/src/collections.rs index c1c0475a..2079a0f3 100644 --- a/core/src/collections.rs +++ b/core/src/collections.rs @@ -123,7 +123,13 @@ impl MongoCollections { .unwrap() .iter() // MHOUSE-7119 - admin database and empty strings are showing in list_database_names - .filter(|&db_name| !db_name.is_empty() && !db_name.eq("admin")) + .filter(|&db_name| { + !db_name.is_empty() + && !db_name.eq("admin") + && !db_name.eq("config") + && !db_name.eq("local") + && !db_name.eq("system") + }) .filter(|&db_name| is_match(db_name, db_name_filter, accept_search_patterns)) .map(|val| async move { CollectionsForDb { diff --git a/core/src/conn.rs b/core/src/conn.rs index a86fbafb..d9935234 100644 --- a/core/src/conn.rs +++ b/core/src/conn.rs @@ -7,7 +7,7 @@ use crate::mongosqltranslate::{ use crate::odbc_uri::UserOptions; use crate::{err::Result, Error}; use crate::{MongoQuery, TypeMode}; -use constants::DRIVER_ODBC_VERSION; +use constants::DRIVER_METRICS_VERSION; use lazy_static::lazy_static; use mongodb::{ bson::{doc, Bson, UuidRepresentation}, @@ -154,7 +154,7 @@ impl MongoConnection { } fn is_libmongosqltranslate_compatible_with_driver_version() -> Result { - let command = CheckDriverVersion::new(DRIVER_ODBC_VERSION.clone()); + let command = CheckDriverVersion::new(DRIVER_METRICS_VERSION.clone()); let command_response = libmongosqltranslate_run_command(command)?; @@ -196,7 +196,7 @@ impl MongoConnection { let uuid_repr = user_options.uuid_representation; - load_mongosqltranslate_library(); + load_mongosqltranslate_library(false); let (is_libmongosqltranslate_compatible_with_driver_version, libmongosqltranslate_version) = if get_mongosqltranslate_library().is_some() { @@ -243,7 +243,7 @@ impl MongoConnection { .is_some_and(|is_compatible| is_compatible) { return Err(Error::LibmongosqltranslateLibraryIsIncompatible( - &DRIVER_ODBC_VERSION, + &DRIVER_METRICS_VERSION, libmongosqltranslate_version .ok_or(Error::EmptyLibmongosqltranslateVersion)?, )); diff --git a/core/src/databases.rs b/core/src/databases.rs index 97c95bf8..8dce2879 100644 --- a/core/src/databases.rs +++ b/core/src/databases.rs @@ -221,7 +221,13 @@ impl MongoDatabases { }) .unwrap() .iter() - .filter(|&db_name| !db_name.is_empty() && !db_name.eq("admin")) + .filter(|&db_name| { + !db_name.is_empty() + && !db_name.eq("admin") + && !db_name.eq("config") + && !db_name.eq("local") + && !db_name.eq("system") + }) .map(|s| s.to_string()) .collect(); diff --git a/core/src/fields.rs b/core/src/fields.rs index 49a09a17..ec483b42 100644 --- a/core/src/fields.rs +++ b/core/src/fields.rs @@ -486,7 +486,13 @@ impl MongoFields { .unwrap() // MHOUSE-7119 - admin database and empty strings are showing in list_database_names .iter() - .filter(|&db_name| !db_name.is_empty() && !db_name.eq("admin")) + .filter(|&db_name| { + !db_name.is_empty() + && !db_name.eq("admin") + && !db_name.eq("config") + && !db_name.eq("local") + && !db_name.eq("system") + }) .map(|s| s.to_string()) .collect() }, diff --git a/core/src/mongosqltranslate.rs b/core/src/mongosqltranslate.rs index 7cfa0ba3..10f0b38b 100644 --- a/core/src/mongosqltranslate.rs +++ b/core/src/mongosqltranslate.rs @@ -42,8 +42,8 @@ fn get_library_name(library_type: &str) -> String { } } -fn get_library_path(library_type: &str) -> PathBuf { - let lib_name = get_library_name(library_type); +fn get_library_path() -> PathBuf { + let lib_name = get_library_name(LIBRARY_NAME); let mut path = PathBuf::from(LIBRARY_INSTALL_PATH); path.push(lib_name); path @@ -63,12 +63,12 @@ fn get_mock_library_path() -> PathBuf { // and is responsible for determining the library name and path. // The library name and path are determined based on the operating system and architecture. // It is stored in a static variable to ensure that it is only loaded once. -pub fn load_mongosqltranslate_library() { +pub fn load_mongosqltranslate_library(mock_library: bool) { INIT.call_once(|| { - let library_path = if cfg!(test) { + let library_path = if mock_library { get_mock_library_path() } else { - get_library_path(LIBRARY_NAME) + get_library_path() }; match unsafe { Library::new(library_path.clone()) } { @@ -221,6 +221,7 @@ impl CheckDriverVersion { } #[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "command_type")] pub enum CommandResponse { Translate(TranslateCommandResponse), GetNamespaces(GetNamespacesCommandResponse), @@ -308,7 +309,7 @@ pub(crate) fn libmongosqltranslate_run_command( let decomposed_returned_doc = unsafe { run_command_function(libmongosqltranslate_command) }; - let command_response_doc: Document = unsafe { + let mut command_response_doc: Document = unsafe { bson::from_slice( Vec::from_raw_parts( decomposed_returned_doc.data.cast_mut(), @@ -320,6 +321,20 @@ pub(crate) fn libmongosqltranslate_run_command( .map_err(Error::LibmongosqltranslateDeserialization)? }; + let command_type = if command_response_doc.get_str("error").is_ok() { + "Error" + } else { + match T::command_name() { + "getNamespaces" => "GetNamespaces", + "translate" => "Translate", + "getMongosqlTranslateVersion" => "GetMongosqlTranslateVersion", + "checkDriverVersion" => "CheckDriverVersion", + _ => unreachable!(), + } + }; + + command_response_doc.insert("command_type", command_type); + let command_response = CommandResponse::from_document(&command_response_doc)?; if let CommandResponse::Error(error_response) = command_response { @@ -340,7 +355,7 @@ mod unit { #[test] fn library_load_and_run_command_test() { - load_mongosqltranslate_library(); + load_mongosqltranslate_library(true); assert!(get_mongosqltranslate_library().is_some()); let run_command = get_run_command_fn_ptr().expect("Failed to load runCommand symbol"); diff --git a/core/src/query.rs b/core/src/query.rs index d522f38c..746f0b0e 100644 --- a/core/src/query.rs +++ b/core/src/query.rs @@ -60,90 +60,113 @@ impl MongoQuery { client: &MongoConnection, db: &Database, ) -> Result { - let schema_collection = db.collection::(SQL_SCHEMAS_COLLECTION); - - let collection_names = namespaces - .iter() - .map(|namespace| namespace.collection.as_str()) - .collect::>(); - - // Create an aggregation pipeline to fetch the schema information for the specified collections. - // The pipeline uses $in to query all the specified collections and projects them into the desired format: - // "dbName": { "collection1" : "Schema1", "collection2" : "Schema2", ... } - let schema_catalog_aggregation_pipeline = vec![ - doc! {"$match": { - "_id": { - "$in": collection_names + let collection_names: Vec = client.runtime.block_on(async { + db.list_collection_names() + .await + .map_err(Error::QueryExecutionFailed) + })?; + + let sql_schemas_collection_exists = + collection_names.contains(&SQL_SCHEMAS_COLLECTION.to_string()); + + if !sql_schemas_collection_exists { + log::warn!("The `__sql_schemas` collection does not exist in database `{0}`. Therefore, there is no schema for the collections in `{0}`, so most queries will fail.", current_db); + } + + let schema_catalog_doc = if !namespaces.is_empty() && sql_schemas_collection_exists { + let schema_collection = db.collection::(SQL_SCHEMAS_COLLECTION); + + let collection_names = namespaces + .iter() + .map(|namespace| namespace.collection.as_str()) + .collect::>(); + + // Create an aggregation pipeline to fetch the schema information for the specified collections. + // The pipeline uses $in to query all the specified collections and projects them into the desired format: + // "dbName": { "collection1" : "Schema1", "collection2" : "Schema2", ... } + let schema_catalog_aggregation_pipeline = vec![ + doc! {"$match": { + "_id": { + "$in": collection_names + } } - } - }, - doc! {"$project":{ - "_id": 1, - "schema": 1 - } - }, - doc! {"$group": { - "_id": null, - "collections": { - "collectionName": "$_id", - "schema": "$schema" + }, + doc! {"$project":{ + "_id": 1, + "schema": 1 } - } - }, - doc! {"$project": { - "_id": 0, - current_db: { - "$arrayToObject": [{ - "$map": { - "input": "$collections", - "as": "coll", - "in": { - "k": "$$coll.collectionName", - "v": "$$coll.schema" - } + }, + doc! {"$group": { + "_id": null, + "collections": { + "$push": { + "collectionName": "$_id", + "schema": "$schema" } - }] + } } - } - }, - ]; + }, + doc! {"$project": { + "_id": 0, + current_db: { + "$arrayToObject": [{ + "$map": { + "input": "$collections", + "as": "coll", + "in": { + "k": "$$coll.collectionName", + "v": "$$coll.schema" + } + } + }] + } + } + }, + ]; + + // create the schema_catalog document + let schema_catalog_doc_vec: Vec = client.runtime.block_on(async { + schema_collection + .aggregate(schema_catalog_aggregation_pipeline) + .await + .map_err(Error::QueryExecutionFailed)? + .try_collect::>() + .await + .map_err(Error::QueryExecutionFailed) + })?; - // create the schema_catalog document - let schema_catalog_doc_vec: Vec = client.runtime.block_on(async { - schema_collection - .aggregate(schema_catalog_aggregation_pipeline) - .await - .map_err(Error::QueryExecutionFailed)? - .try_collect::>() - .await - .map_err(Error::QueryExecutionFailed) - })?; + if schema_catalog_doc_vec.len() > 1 { + return Err(Error::MultipleSchemaDocumentsReturned( + schema_catalog_doc_vec.len(), + )); + } else if schema_catalog_doc_vec.is_empty() { + return Err(Error::NoSchemaInformationReturned); + } - if schema_catalog_doc_vec.len() > 1 { - return Err(Error::MultipleSchemaDocumentsReturned( - schema_catalog_doc_vec.len(), - )); - } else if schema_catalog_doc_vec.is_empty() { - return Err(Error::NoSchemaInformationReturned); - } + let schema_catalog_doc = schema_catalog_doc_vec[0].to_owned(); - let schema_catalog_doc = schema_catalog_doc_vec[0].to_owned(); + let collections_schema_doc = schema_catalog_doc + .get_document(current_db) + .map_err(|e: ValueAccessError| Error::ValueAccess(current_db.to_string(), e))?; - let collections_schema_doc = schema_catalog_doc - .get_document(current_db) - .map_err(|e: ValueAccessError| Error::ValueAccess(current_db.to_string(), e))?; + if namespaces.len() != collections_schema_doc.len() { + let missing_collections: Vec = namespaces + .iter() + .map(|namespace| namespace.collection.clone()) + .filter(|collection| !collections_schema_doc.contains_key(collection.as_str())) + .collect(); - if namespaces.len() != collections_schema_doc.len() { - let missing_collections: Vec = namespaces - .iter() - .map(|namespace| namespace.collection.clone()) - .filter(|collection| !collections_schema_doc.contains_key(collection.as_str())) - .collect(); + return Err(Error::SchemaDocumentNotFoundInSchemaCollection( + missing_collections, + )); + } - return Err(Error::SchemaDocumentNotFoundInSchemaCollection( - missing_collections, - )); - } + schema_catalog_doc + } else { + doc! { + current_db: doc! {}, + } + }; let command = Translate::new( sql_query.to_string(), diff --git a/core/src/util/test_connection.rs b/core/src/util/test_connection.rs index b82df17d..5dfdd8e1 100644 --- a/core/src/util/test_connection.rs +++ b/core/src/util/test_connection.rs @@ -120,7 +120,6 @@ mod test { } #[test] - #[ignore = "SQL-2288: need real libmongosqltranslate"] #[cfg(feature = "bad_host")] fn bad_host() { let mut buffer = [0; 1024]; diff --git a/evergreen.yml b/evergreen.yml index 472b5f4f..681d4c06 100644 --- a/evergreen.yml +++ b/evergreen.yml @@ -1417,60 +1417,85 @@ functions: # Stop the local ADF ./resources/run_adf.sh stop exit $EXITCODE + + "run mongosqltranslate integration test": + - command: s3.get + params: + aws_key: ${aws_key} + aws_secret: ${aws_secret} + remote_file: mongosql-rs/artifacts/67046714cb2efd0007eb7608/mongosqltranslate-rhel76/libmongosqltranslate.so + local_file: mongosql-odbc-driver/libmongosqltranslate.so + bucket: mciuploads + - command: shell.exec + type: test + params: + shell: bash + working_dir: mongosql-odbc-driver + script: | + ${prepare_shell} + sudo mkdir -p /opt/mongodb/atlas-sql-odbc-driver/ + sudo mv -f libmongosqltranslate.so /opt/mongodb/atlas-sql-odbc-driver/libmongosqltranslate.so + cargo test mongosqltranslate -- --nocapture "run ubuntu cluster type integration test": - command: shell.exec - type: test - params: - shell: bash - working_dir: mongosql-odbc-driver - script: | - ${prepare_shell} + - command: s3.get + params: + aws_key: ${aws_key} + aws_secret: ${aws_secret} + remote_file: mongosql-rs/artifacts/67046714cb2efd0007eb7608/mongosqltranslate-rhel76/libmongosqltranslate.so + local_file: mongosql-odbc-driver/libmongosqltranslate.so + bucket: mciuploads + - command: shell.exec + type: test + params: + shell: bash + working_dir: mongosql-odbc-driver + script: | + ${prepare_shell} - mdb_version_com="mongodb-linux-x86_64-ubuntu2204-7.0.14" - mdb_version_ent="mongodb-linux-x86_64-enterprise-ubuntu2204-7.0.14" - arch="x64" + mdb_version_com="mongodb-linux-x86_64-ubuntu2204-7.0.14" + mdb_version_ent="mongodb-linux-x86_64-enterprise-ubuntu2204-7.0.14" + arch="x64" - # Start MongoDB instances - ./resources/start_local_mdb.sh $mdb_version_com $mdb_version_ent $arch + # Start MongoDB instances + ./resources/start_local_mdb.sh $mdb_version_com $mdb_version_ent $arch - # Enterprise test without library - cargo test --features cluster_type_tests -- \ - cluster_type::test_determine_cluster_type_enterprise_fails_without_library --nocapture - ENTERPRISE_NOLIB_EXITCODE=$? + # Enterprise test without library + cargo test --features cluster_type_tests -- \ + cluster_type::test_determine_cluster_type_enterprise_fails_without_library --nocapture + ENTERPRISE_NOLIB_EXITCODE=$? - # Build and move mock mongosqltranslate library - cargo build --package mock_mongosqltranslate - sudo mkdir -p /opt/mongodb/atlas-sql-odbc-driver/ - sudo mv -f ./target/debug/libmock_mongosqltranslate.so /opt/mongodb/atlas-sql-odbc-driver/libmongosqltranslate.so + # Move mongosqltranslate library to the correct location + sudo mkdir -p /opt/mongodb/atlas-sql-odbc-driver/ + sudo mv -f libmongosqltranslate.so /opt/mongodb/atlas-sql-odbc-driver/libmongosqltranslate.so - # Enterprise test with library - cargo test --features cluster_type_tests -- \ - cluster_type::test_enterprise_with_library_fails_due_to_missing_sql_get_result_schema_command --nocapture - ENTERPRISE_LIB_EXITCODE=$? + # Enterprise test with library + cargo test --features cluster_type_tests -- \ + cluster_type::test_enterprise_with_library_fails_due_to_missing_sql_get_result_schema_command --nocapture + ENTERPRISE_LIB_EXITCODE=$? - # Community test - cargo test --features cluster_type_tests -- cluster_type::test_determine_cluster_type_community_fails --nocapture - COMMUNITY_EXITCODE=$? + # Community test + cargo test --features cluster_type_tests -- cluster_type::test_determine_cluster_type_community_fails --nocapture + COMMUNITY_EXITCODE=$? - # Stop MongoDB instances - pkill mongod + # Stop MongoDB instances + pkill mongod - # Determine overall exit code - if [ $ENTERPRISE_NOLIB_EXITCODE -eq 0 ] && [ $ENTERPRISE_LIB_EXITCODE -eq 0 ] && [ $COMMUNITY_EXITCODE -eq 0 ]; then - OVERALL_EXITCODE=0 - else - OVERALL_EXITCODE=1 - fi + # Determine overall exit code + if [ $ENTERPRISE_NOLIB_EXITCODE -eq 0 ] && [ $ENTERPRISE_LIB_EXITCODE -eq 0 ] && [ $COMMUNITY_EXITCODE -eq 0 ]; then + OVERALL_EXITCODE=0 + else + OVERALL_EXITCODE=1 + fi - echo "Cluster test results:" - echo "Enterprise test without library exit code: $ENTERPRISE_NOLIB_EXITCODE" - echo "Enterprise test with library exit code: $ENTERPRISE_LIB_EXITCODE" - echo "Community test exit code: $COMMUNITY_EXITCODE" - echo "Overall exit code: $OVERALL_EXITCODE" + echo "Cluster test results:" + echo "Enterprise test without library exit code: $ENTERPRISE_NOLIB_EXITCODE" + echo "Enterprise test with library exit code: $ENTERPRISE_LIB_EXITCODE" + echo "Community test exit code: $COMMUNITY_EXITCODE" + echo "Overall exit code: $OVERALL_EXITCODE" - exit $OVERALL_EXITCODE + exit $OVERALL_EXITCODE "run macos result-set tests": - command: shell.exec @@ -1981,7 +2006,9 @@ tasks: - func: "run ubuntu integration tests" variants: [ubuntu2204] - func: "run ubuntu cluster type integration test" - variants: [ ubuntu2204 ] + variants: [ubuntu2204] + - func: "run mongosqltranslate integration test" + variants: [ubuntu2204] # Commenting out because the following task only detects # memory leaks in the tests # - func: "run asan integration tests" diff --git a/integration_test/tests/bind_cols_tests.rs b/integration_test/tests/bind_cols_tests.rs index d4220aaf..6d995b4a 100644 --- a/integration_test/tests/bind_cols_tests.rs +++ b/integration_test/tests/bind_cols_tests.rs @@ -34,7 +34,7 @@ mod integration { #[test] fn test_unbind_cols() { let (_, _, stmt_handle) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3, None); unsafe { exec_direct_default_query(stmt_handle); @@ -91,7 +91,7 @@ mod integration { #[test] fn test_bind_cols_and_fetch_next_rowset() { let (_, _, stmt_handle) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3, None); unsafe { const ROW_ARRAY_SIZE: usize = 2; diff --git a/integration_test/tests/cluster_type_test.rs b/integration_test/tests/cluster_type_test.rs index 7469891e..f0fc12f0 100644 --- a/integration_test/tests/cluster_type_test.rs +++ b/integration_test/tests/cluster_type_test.rs @@ -11,7 +11,6 @@ mod cluster_type { use std::env; #[derive(Debug)] - #[allow(dead_code)] enum PortType { Enterprise, Community, @@ -68,7 +67,6 @@ mod cluster_type { // Tests that connection with community edition fails #[tokio::test] - #[ignore = "SQL-2288: need real libmongosqltranslate"] async fn test_determine_cluster_type_community_fails() { let result = run_cluster_type_test(PortType::Community).await; assert!( @@ -88,20 +86,12 @@ mod cluster_type { // Tests that connection with enterprise edition and library loaded fails // due to missing 'sqlGetResultSchema' command in MongoDB #[tokio::test] - #[ignore = "SQL-2288: need real libmongosqltranslate"] - async fn test_enterprise_with_library_fails_due_to_missing_sql_get_result_schema_command() { + async fn test_enterprise_with_library_succeeds() { let result = run_cluster_type_test(PortType::Enterprise).await; assert!( - result.is_err(), - "Expected an error with enterprise edition and library loaded, but got success" + result.is_ok(), + "Expected success with enterprise edition and library loaded, but got an error" ); - if let Err(e) = result { - assert!( - e.contains("no such command: 'sqlGetResultSchema'"), - "Unexpected error message for enterprise edition: {}", - e - ); - } } // Test that connecting with enterprise edition cluster type fails without mongosqltranslate library diff --git a/integration_test/tests/common/mod.rs b/integration_test/tests/common/mod.rs index 38106926..49d1fb06 100644 --- a/integration_test/tests/common/mod.rs +++ b/integration_test/tests/common/mod.rs @@ -83,11 +83,16 @@ pub fn generate_default_connection_str() -> String { #[allow(dead_code)] /// generate a "mongodb+srv" connection string based on the specified environmental variables. -pub fn generate_srv_style_connection_string() -> String { +pub fn generate_srv_style_connection_string(db: Option) -> String { // The driver used is the same as the one used for ADF let driver = env::var("ADF_TEST_LOCAL_DRIVER").unwrap_or_else(|_e| DRIVER_NAME.to_string()); - let db = env::var("SRV_TEST_DB").expect("SRV_TEST_DB is not set"); + let db = if let Some(db) = db { + db + } else { + env::var("SRV_TEST_DB").expect("SRV_TEST_DB is not set") + }; + let auth_db = env::var("SRV_TEST_AUTH_DB").expect("SRV_TEST_AUTH_DB is not set"); let host = env::var("SRV_TEST_HOST").expect("SRV_TEST_HOST is not set"); let username = env::var("SRV_TEST_USER").expect("SRV_TEST_USER is not set"); @@ -154,9 +159,11 @@ pub fn sql_return_to_string(return_code: SqlReturn) -> String { /// - SQLAllocHandle(SQL_HANDLE_STMT) pub fn default_setup_connect_and_alloc_stmt( odbc_version_value: AttrOdbcVersion, + in_connection_string: Option, ) -> (HEnv, HDbc, HStmt) { let env_handle = allocate_env(odbc_version_value); - let (conn_handle, stmt_handle) = connect_and_allocate_statement(env_handle, None); + let (conn_handle, stmt_handle) = + connect_and_allocate_statement(env_handle, in_connection_string); (env_handle, conn_handle, stmt_handle) } diff --git a/integration_test/tests/connection_tests.rs b/integration_test/tests/connection_tests.rs index 1802a007..7db6f287 100644 --- a/integration_test/tests/connection_tests.rs +++ b/integration_test/tests/connection_tests.rs @@ -9,7 +9,7 @@ mod common; mod integration { use crate::common::{ allocate_env, connect_and_allocate_statement, connect_with_conn_string, - disconnect_and_close_handles, Error, + disconnect_and_close_handles, }; use constants::DRIVER_NAME; use cstr::{to_char_ptr, to_widechar_ptr, WideChar}; @@ -43,19 +43,6 @@ mod integration { let _ = unsafe { Box::from_raw(env_handle) }; } - #[test] - fn test_srv_style_uri_connection() { - let env_handle = allocate_env(AttrOdbcVersion::SQL_OV_ODBC3); - let conn_str = crate::common::generate_srv_style_connection_string(); - let result = connect_with_conn_string(env_handle, Some(conn_str)); - - // TODO: SQL-2291: Uncomment the below assert!() and remove the uncommented one. - // assert!(connection_result.is_ok(), "Expected successful connection, got error: {:?}", connection_result); - assert!(matches!(result, Err(Error::DriverConnect(_, _)))); - - let _ = unsafe { Box::from_raw(env_handle) }; - } - #[test] fn uuid_csharp_legacy() { let env_handle = allocate_env(AttrOdbcVersion::SQL_OV_ODBC3); diff --git a/integration_test/tests/free_and_cancel_tests.rs b/integration_test/tests/free_and_cancel_tests.rs index 6cc024a6..c4551ad7 100644 --- a/integration_test/tests/free_and_cancel_tests.rs +++ b/integration_test/tests/free_and_cancel_tests.rs @@ -38,7 +38,7 @@ mod integration { #[test] fn test_free_stmt() { let (env_handle, conn_handle, stmt_handle) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3, None); unsafe { let mut query: Vec = @@ -76,7 +76,7 @@ mod integration { #[test] fn test_cancel_noop() { let (_, _, stmt_handle) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3, None); unsafe { let timeout: i32 = 15; diff --git a/integration_test/tests/get_data_tests.rs b/integration_test/tests/get_data_tests.rs index c03dbfad..e018b07b 100644 --- a/integration_test/tests/get_data_tests.rs +++ b/integration_test/tests/get_data_tests.rs @@ -112,7 +112,7 @@ mod integration { for buffer_size in buffer_sizes { let (env_handle, conn_handle, stmt_handle) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3, None); unsafe { let query = b"SELECT * FROM integration_test.class\0".map(|c| c.into()); diff --git a/integration_test/tests/mongosqltranslate_tests.rs b/integration_test/tests/mongosqltranslate_tests.rs new file mode 100644 index 00000000..97f795ba --- /dev/null +++ b/integration_test/tests/mongosqltranslate_tests.rs @@ -0,0 +1,158 @@ +mod common; + +#[cfg(test)] +mod mongosqltranslate { + use crate::common::{ + allocate_env, connect_with_conn_string, default_setup_connect_and_alloc_stmt, + disconnect_and_close_handles, fetch_and_get_data, get_column_attributes, + get_sql_diagnostics, + }; + use cstr::WideChar; + use definitions::{ + AttrOdbcVersion, CDataType, HStmt, Handle, HandleType, SQLExecDirectW, SQLExecute, + SQLPrepareW, SqlReturn, SQL_NTS, + }; + + #[test] + fn test_srv_style_uri_connection() { + let env_handle = allocate_env(AttrOdbcVersion::SQL_OV_ODBC3); + let conn_str = + crate::common::generate_srv_style_connection_string(Some("test".to_string())); + let result = connect_with_conn_string(env_handle, Some(conn_str)); + + assert!( + result.is_ok(), + "Expected successful connection, got error: {:?}", + result + ); + + let _ = unsafe { Box::from_raw(env_handle) }; + } + + #[test] + fn test_sql_prepare_and_sql_execute_with_library_loaded_and_valid_query_and_valid_schemas_created( + ) { + let (env_handle, dbc, stmt) = default_setup_connect_and_alloc_stmt( + AttrOdbcVersion::SQL_OV_ODBC3, + Some(crate::common::generate_srv_style_connection_string(Some( + "sample_airbnb".to_string(), + ))), + ); + + unsafe { + let mut query: Vec = cstr::to_widechar_vec("SELECT property_type, room_type, bed_type, minimum_nights, maximum_nights FROM listingsAndReviews LIMIT 3"); + query.push(0); + + assert_eq!( + SqlReturn::SUCCESS, + SQLPrepareW(stmt as HStmt, query.as_ptr(), SQL_NTS), + "{}", + get_sql_diagnostics(HandleType::SQL_HANDLE_STMT, stmt as Handle) + ); + + get_column_attributes(stmt as Handle, 5); + + assert_eq!( + SqlReturn::SUCCESS, + SQLExecute(stmt as HStmt), + "{}", + get_sql_diagnostics(HandleType::SQL_HANDLE_STMT, stmt as Handle) + ); + + fetch_and_get_data( + stmt as Handle, + Some(3), + vec![SqlReturn::SUCCESS; 5], + vec![CDataType::SQL_C_WCHAR; 5], + ); + + disconnect_and_close_handles(dbc, stmt); + } + let _ = unsafe { Box::from_raw(env_handle) }; + } + + #[test] + fn test_sql_execute_direct_with_library_loaded_and_valid_query_and_valid_schemas_created() { + let (env_handle, dbc, stmt) = default_setup_connect_and_alloc_stmt( + AttrOdbcVersion::SQL_OV_ODBC3, + Some(crate::common::generate_srv_style_connection_string(Some( + "sample_airbnb".to_string(), + ))), + ); + + unsafe { + let mut query: Vec = cstr::to_widechar_vec("SELECT property_type, room_type, bed_type, minimum_nights, maximum_nights FROM listingsAndReviews LIMIT 3"); + query.push(0); + + assert_eq!( + SqlReturn::SUCCESS, + SQLExecDirectW(stmt as HStmt, query.as_ptr(), SQL_NTS), + "{}", + get_sql_diagnostics(HandleType::SQL_HANDLE_STMT, stmt as Handle) + ); + + get_column_attributes(stmt as Handle, 5); + + fetch_and_get_data( + stmt as Handle, + Some(3), + vec![SqlReturn::SUCCESS; 5], + vec![CDataType::SQL_C_WCHAR; 5], + ); + + disconnect_and_close_handles(dbc, stmt); + } + let _ = unsafe { Box::from_raw(env_handle) }; + } + + #[test] + fn test_enterprise_mode_with_library_loaded_and_invalid_query_and_valid_schemas_created() { + let (env_handle, dbc, stmt) = default_setup_connect_and_alloc_stmt( + AttrOdbcVersion::SQL_OV_ODBC3, + Some(crate::common::generate_srv_style_connection_string(Some( + "sample_airbnb".to_string(), + ))), + ); + + unsafe { + let mut query: Vec = + cstr::to_widechar_vec("select * from non_existent_collection"); + query.push(0); + + assert_eq!( + SqlReturn::ERROR, + SQLPrepareW(stmt as HStmt, query.as_ptr(), SQL_NTS), + "{}", + get_sql_diagnostics(HandleType::SQL_HANDLE_STMT, stmt as Handle) + ); + + disconnect_and_close_handles(dbc, stmt); + } + let _ = unsafe { Box::from_raw(env_handle) }; + } + + #[test] + fn test_enterprise_mode_with_library_loaded_and_valid_query_and_no_sql_schemas_collection() { + let (env_handle, dbc, stmt) = default_setup_connect_and_alloc_stmt( + AttrOdbcVersion::SQL_OV_ODBC3, + Some(crate::common::generate_srv_style_connection_string(Some( + "test".to_string(), + ))), + ); + + unsafe { + let mut query: Vec = cstr::to_widechar_vec("select * from foo"); + query.push(0); + + assert_eq!( + SqlReturn::ERROR, + SQLPrepareW(stmt as HStmt, query.as_ptr(), SQL_NTS), + "{}", + get_sql_diagnostics(HandleType::SQL_HANDLE_STMT, stmt as Handle) + ); + + disconnect_and_close_handles(dbc, stmt); + } + let _ = unsafe { Box::from_raw(env_handle) }; + } +} diff --git a/integration_test/tests/odbc_2_tests.rs b/integration_test/tests/odbc_2_tests.rs index 87a6d7f3..150fac24 100644 --- a/integration_test/tests/odbc_2_tests.rs +++ b/integration_test/tests/odbc_2_tests.rs @@ -29,7 +29,7 @@ mod integration { #[test] fn test_list_tables() { let (env_handle, conn_handle, stmt_handle) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC2); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC2, None); unsafe { let mut table_view: Vec = cstr::to_widechar_vec("TABLE"); @@ -105,6 +105,8 @@ mod integration { /// call SQLGetTypeInfo to verify the correct types are returned. For all types, /// we should get both date types back. For date, we should get the specific date type /// we expect back. + /// + /// NOTE: FLAKY TEST #[test] fn test_type_listing() { let env_handle = allocate_env(AttrOdbcVersion::SQL_OV_ODBC2); diff --git a/integration_test/tests/prepared_statement_tests.rs b/integration_test/tests/prepared_statement_tests.rs index 03fea2bf..e9447829 100644 --- a/integration_test/tests/prepared_statement_tests.rs +++ b/integration_test/tests/prepared_statement_tests.rs @@ -21,7 +21,7 @@ mod integration { #[test] fn test_error_execute_before_prepare() { let (env_handle, dbc, stmt) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3, None); let mut query: Vec = cstr::to_widechar_vec("select * from example"); query.push(0); @@ -41,7 +41,7 @@ mod integration { #[test] fn test_prepare_get_resultset_metadata() { let (env_handle, dbc, stmt) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3, None); unsafe { let mut query: Vec = cstr::to_widechar_vec("select * from example"); @@ -66,7 +66,7 @@ mod integration { #[test] fn test_error_fetch_before_execute() { let (env_handle, dbc, stmt) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3, None); unsafe { let mut query: Vec = cstr::to_widechar_vec("select * from example"); @@ -94,7 +94,7 @@ mod integration { #[test] fn test_prepare_execute_retrieve_data() { let (env_handle, dbc, stmt) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3, None); unsafe { let mut query: Vec = cstr::to_widechar_vec("select * from example"); @@ -140,7 +140,7 @@ mod integration { #[test] fn test_prepare_execute_multiple_times() { let (env_handle, dbc, stmt) = - default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3); + default_setup_connect_and_alloc_stmt(AttrOdbcVersion::SQL_OV_ODBC3, None); unsafe { let mut query: Vec = cstr::to_widechar_vec("select * from example"); From ac45b5dc74e9f2d780d58a4557a8808b8583dbea Mon Sep 17 00:00:00 2001 From: Ethan Hardy Date: Tue, 15 Oct 2024 12:55:58 -0400 Subject: [PATCH 4/9] fix evergreen names --- evergreen.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/evergreen.yml b/evergreen.yml index 681d4c06..89c8e3d0 100644 --- a/evergreen.yml +++ b/evergreen.yml @@ -1418,7 +1418,7 @@ functions: ./resources/run_adf.sh stop exit $EXITCODE - "run mongosqltranslate integration test": + "run mongosqltranslate integration tests": - command: s3.get params: aws_key: ${aws_key} @@ -1438,7 +1438,7 @@ functions: cargo test mongosqltranslate -- --nocapture - "run ubuntu cluster type integration test": + "run ubuntu cluster type integration tests": - command: s3.get params: aws_key: ${aws_key} @@ -2005,9 +2005,9 @@ tasks: - func: "generate github token" - func: "run ubuntu integration tests" variants: [ubuntu2204] - - func: "run ubuntu cluster type integration test" + - func: "run ubuntu cluster type integration tests" variants: [ubuntu2204] - - func: "run mongosqltranslate integration test" + - func: "run mongosqltranslate integration tests" variants: [ubuntu2204] # Commenting out because the following task only detects # memory leaks in the tests From 2ca83d063d35bc2dc77ec05f42f0d46ae7164ad8 Mon Sep 17 00:00:00 2001 From: Ethan Hardy Date: Tue, 15 Oct 2024 13:14:26 -0400 Subject: [PATCH 5/9] remove test flag --- integration_test/tests/mongosqltranslate_tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/integration_test/tests/mongosqltranslate_tests.rs b/integration_test/tests/mongosqltranslate_tests.rs index 97f795ba..f18866e2 100644 --- a/integration_test/tests/mongosqltranslate_tests.rs +++ b/integration_test/tests/mongosqltranslate_tests.rs @@ -1,6 +1,5 @@ mod common; -#[cfg(test)] mod mongosqltranslate { use crate::common::{ allocate_env, connect_with_conn_string, default_setup_connect_and_alloc_stmt, From d3645cfb57f2514a30d77b876d489b7de124946f Mon Sep 17 00:00:00 2001 From: Ethan Hardy Date: Tue, 15 Oct 2024 13:28:02 -0400 Subject: [PATCH 6/9] rename evergreen mongosqltranslate task --- evergreen.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evergreen.yml b/evergreen.yml index 89c8e3d0..b3488cbb 100644 --- a/evergreen.yml +++ b/evergreen.yml @@ -1418,7 +1418,7 @@ functions: ./resources/run_adf.sh stop exit $EXITCODE - "run mongosqltranslate integration tests": + "run ubuntu mongosqltranslate integration tests": - command: s3.get params: aws_key: ${aws_key} @@ -2007,7 +2007,7 @@ tasks: variants: [ubuntu2204] - func: "run ubuntu cluster type integration tests" variants: [ubuntu2204] - - func: "run mongosqltranslate integration tests" + - func: "run ubuntu mongosqltranslate integration tests" variants: [ubuntu2204] # Commenting out because the following task only detects # memory leaks in the tests From 2f9c33001453c5db311399dea7b20fb25ec445f5 Mon Sep 17 00:00:00 2001 From: Ethan Hardy Date: Tue, 15 Oct 2024 15:28:35 -0400 Subject: [PATCH 7/9] change version back to 0.0.0 --- Cargo.lock | 2 +- constants/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 777f2051..0cf4f67c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -571,7 +571,7 @@ dependencies = [ [[package]] name = "constants" -version = "2.0.0" +version = "0.0.0" dependencies = [ "anyhow", "cargo_toml", diff --git a/constants/Cargo.toml b/constants/Cargo.toml index 8ebdfb21..2c8af76e 100644 --- a/constants/Cargo.toml +++ b/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "constants" -version = "2.0.0" +version = "0.0.0" authors = [ "Ryan Chipman ", "Natacha Bagnard ", From faba35f2b86ed13b116cf80d146df013051b651b Mon Sep 17 00:00:00 2001 From: Ethan Hardy Date: Tue, 15 Oct 2024 16:03:55 -0400 Subject: [PATCH 8/9] change mongosqltranslate library used in evergreen --- evergreen.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/evergreen.yml b/evergreen.yml index b3488cbb..a42b5393 100644 --- a/evergreen.yml +++ b/evergreen.yml @@ -1423,9 +1423,9 @@ functions: params: aws_key: ${aws_key} aws_secret: ${aws_secret} - remote_file: mongosql-rs/artifacts/67046714cb2efd0007eb7608/mongosqltranslate-rhel76/libmongosqltranslate.so + remote_file: mongosqltranslate/snapshot/libmongosqltranslate-linux.so local_file: mongosql-odbc-driver/libmongosqltranslate.so - bucket: mciuploads + bucket: translators-connectors-releases - command: shell.exec type: test params: @@ -1443,9 +1443,9 @@ functions: params: aws_key: ${aws_key} aws_secret: ${aws_secret} - remote_file: mongosql-rs/artifacts/67046714cb2efd0007eb7608/mongosqltranslate-rhel76/libmongosqltranslate.so + remote_file: mongosqltranslate/snapshot/libmongosqltranslate-linux.so local_file: mongosql-odbc-driver/libmongosqltranslate.so - bucket: mciuploads + bucket: translators-connectors-releases - command: shell.exec type: test params: From b17ce9e9f07e70c6b3dd16392a901dd8fa8ba6d2 Mon Sep 17 00:00:00 2001 From: Ethan Hardy Date: Thu, 17 Oct 2024 17:06:41 -0400 Subject: [PATCH 9/9] respond to some feedback --- core/src/col_metadata.rs | 5 ++- core/src/collections.rs | 10 +---- core/src/conn.rs | 2 + core/src/databases.rs | 10 +---- core/src/fields.rs | 39 +++++++++---------- core/src/mongosqltranslate.rs | 5 +++ core/src/util/mod.rs | 8 ++++ .../tests/mongosqltranslate_tests.rs | 14 +++++++ 8 files changed, 56 insertions(+), 37 deletions(-) diff --git a/core/src/col_metadata.rs b/core/src/col_metadata.rs index 4fdbfa4c..1a27ae63 100644 --- a/core/src/col_metadata.rs +++ b/core/src/col_metadata.rs @@ -171,9 +171,12 @@ pub struct VersionedJsonSchema { } // Struct representing the ResultSetSchema. +// The `schema` field needs the alias `result_set_schema` because this struct is used to get the schema +// from the __sql_schemas collection, which stores the schema in it's `schema` field, and the libmongosqltranslate +// `translate` command, which stores the schema in it's `result_set_schema` field. #[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Default)] pub struct ResultSetSchema { - #[serde(rename = "result_set_schema")] + #[serde(alias = "result_set_schema")] pub schema: crate::json_schema::Schema, #[serde(skip_serializing_if = "Option::is_none")] pub select_order: Option>>, diff --git a/core/src/collections.rs b/core/src/collections.rs index 2079a0f3..28ebaab4 100644 --- a/core/src/collections.rs +++ b/core/src/collections.rs @@ -1,5 +1,5 @@ use crate::stmt::EmptyStatement; -use crate::util::{is_match, table_type_filter_to_vec, to_name_regex}; +use crate::util::{databases_filter, is_match, table_type_filter_to_vec, to_name_regex}; use crate::{ col_metadata::MongoColMetadata, conn::MongoConnection, @@ -123,13 +123,7 @@ impl MongoCollections { .unwrap() .iter() // MHOUSE-7119 - admin database and empty strings are showing in list_database_names - .filter(|&db_name| { - !db_name.is_empty() - && !db_name.eq("admin") - && !db_name.eq("config") - && !db_name.eq("local") - && !db_name.eq("system") - }) + .filter(|&db_name| databases_filter(db_name)) .filter(|&db_name| is_match(db_name, db_name_filter, accept_search_patterns)) .map(|val| async move { CollectionsForDb { diff --git a/core/src/conn.rs b/core/src/conn.rs index d9935234..5471183d 100644 --- a/core/src/conn.rs +++ b/core/src/conn.rs @@ -214,6 +214,8 @@ impl MongoConnection { let compatibility = Self::is_libmongosqltranslate_compatible_with_driver_version()?; + log::info!("libmongosqltranslate version: `{0}`. ODBC driver version: `{1}`. The ODBC driver and libmongosqltranslate library is compatible: `{2}`.", libmongosqltranslate_version, *DRIVER_METRICS_VERSION, compatibility); + (Some(compatibility), Some(libmongosqltranslate_version)) } else { (None, None) diff --git a/core/src/databases.rs b/core/src/databases.rs index 8dce2879..9c9a04cc 100644 --- a/core/src/databases.rs +++ b/core/src/databases.rs @@ -1,6 +1,6 @@ use crate::{ col_metadata::MongoColMetadata, conn::MongoConnection, err::Result, stmt::MongoStatement, - BsonTypeInfo, Error, + util::databases_filter, BsonTypeInfo, Error, }; use definitions::Nullability; use mongodb::bson::Bson; @@ -221,13 +221,7 @@ impl MongoDatabases { }) .unwrap() .iter() - .filter(|&db_name| { - !db_name.is_empty() - && !db_name.eq("admin") - && !db_name.eq("config") - && !db_name.eq("local") - && !db_name.eq("system") - }) + .filter(|&db_name| databases_filter(db_name)) .map(|s| s.to_string()) .collect(); diff --git a/core/src/fields.rs b/core/src/fields.rs index ec483b42..8c47262f 100644 --- a/core/src/fields.rs +++ b/core/src/fields.rs @@ -5,7 +5,7 @@ use crate::{ conn::MongoConnection, err::{Error, Result}, stmt::MongoStatement, - util::to_name_regex, + util::{databases_filter, to_name_regex}, BsonTypeInfo, TypeMode, }; use constants::SQL_SCHEMAS_COLLECTION; @@ -486,13 +486,7 @@ impl MongoFields { .unwrap() // MHOUSE-7119 - admin database and empty strings are showing in list_database_names .iter() - .filter(|&db_name| { - !db_name.is_empty() - && !db_name.eq("admin") - && !db_name.eq("config") - && !db_name.eq("local") - && !db_name.eq("system") - }) + .filter(|&db_name| databases_filter(db_name)) .map(|s| s.to_string()) .collect() }, @@ -567,13 +561,17 @@ impl MongoFields { Error::CollectionDeserialization(collection_name.clone(), e) }); - if let Err(error) = sql_get_schema_response { - // If there is an Error while deserializing the schema, we won't show any columns for it - warnings.push(error); - continue; - } + let error_checked_sql_get_schema_response = + match sql_get_schema_response { + Ok(sql_get_schema_response) => sql_get_schema_response, + Err(error) => { + // If there is an Error while deserializing the schema, we won't show any columns for it + warnings.push(error); + continue; + } + }; - sql_get_schema_response.unwrap().into() + error_checked_sql_get_schema_response.into() } else if mongo_connection.cluster_type == MongoClusterType::Enterprise { let schema_collection = db.collection::(SQL_SCHEMAS_COLLECTION); @@ -599,13 +597,14 @@ impl MongoFields { }, ); - if let Err(error) = result_set_schema { - // If there is an Error while deserializing the schema, we won't show any columns for it - warnings.push(error); - continue; + match result_set_schema { + Ok(result_set_schema) => result_set_schema, + Err(error) => { + // If there is an Error while deserializing the schema, we won't show any columns for it + warnings.push(error); + continue; + } } - - result_set_schema.unwrap() } else { unreachable!() }; diff --git a/core/src/mongosqltranslate.rs b/core/src/mongosqltranslate.rs index 10f0b38b..b136d3e1 100644 --- a/core/src/mongosqltranslate.rs +++ b/core/src/mongosqltranslate.rs @@ -307,6 +307,11 @@ pub(crate) fn libmongosqltranslate_run_command( capacity: command_bytes_capacity, }; + log::info!( + "Calling `{}` libmongosqltranslate runCommand.", + T::command_name() + ); + let decomposed_returned_doc = unsafe { run_command_function(libmongosqltranslate_command) }; let mut command_response_doc: Document = unsafe { diff --git a/core/src/util/mod.rs b/core/src/util/mod.rs index 8dab2121..1db87075 100644 --- a/core/src/util/mod.rs +++ b/core/src/util/mod.rs @@ -78,6 +78,14 @@ pub(crate) fn table_type_filter_to_vec(table_type: &str) -> Option bool { + !db_name.is_empty() + && !db_name.eq("admin") + && !db_name.eq("config") + && !db_name.eq("local") + && !db_name.eq("system") +} + #[macro_export] macro_rules! map { ($($key:expr => $val:expr),* $(,)?) => { diff --git a/integration_test/tests/mongosqltranslate_tests.rs b/integration_test/tests/mongosqltranslate_tests.rs index f18866e2..ca8b3938 100644 --- a/integration_test/tests/mongosqltranslate_tests.rs +++ b/integration_test/tests/mongosqltranslate_tests.rs @@ -125,6 +125,13 @@ mod mongosqltranslate { get_sql_diagnostics(HandleType::SQL_HANDLE_STMT, stmt as Handle) ); + let error_message = get_sql_diagnostics(HandleType::SQL_HANDLE_STMT, stmt as Handle); + assert!( + error_message.contains("No schema information returned for the requested collections."), + "Expected error message: `No schema information returned for the requested collections.`; actual error message: {}", + error_message + ); + disconnect_and_close_handles(dbc, stmt); } let _ = unsafe { Box::from_raw(env_handle) }; @@ -150,6 +157,13 @@ mod mongosqltranslate { get_sql_diagnostics(HandleType::SQL_HANDLE_STMT, stmt as Handle) ); + let error_message = get_sql_diagnostics(HandleType::SQL_HANDLE_STMT, stmt as Handle); + assert!( + error_message.contains("The libmongosqltranslate command `translate` failed. Error message: `algebrize error: Error 1016: unknown collection 'foo' in database 'test'`. Error is internal: false"), + "Expected error message: `The libmongosqltranslate command `translate` failed. Error message: `algebrize error: Error 1016: unknown collection 'foo' in database 'test'`. Error is internal: false`; actual error message: {}", + error_message + ); + disconnect_and_close_handles(dbc, stmt); } let _ = unsafe { Box::from_raw(env_handle) };