feat: extend InfluxQL rewriter for SELECT and EXPLAIN (#24726)

Extended the InfluxQL rewriter to handle SELECT statements with nested
sub-queries, as well as EXPLAIN statements.

Tests were added to check all the rewrite cases for happy path and
failure modes.
pull/24737/head
Trevor Hilton 2024-03-05 15:40:16 -05:00 committed by GitHub
parent 160ac34edd
commit 423308dcd4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 513 additions and 96 deletions

130
Cargo.lock generated
View File

@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.8.10"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"const-random",
@ -132,9 +132,9 @@ checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
[[package]]
name = "arc-swap"
version = "1.6.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f"
[[package]]
name = "arrayref"
@ -523,11 +523,11 @@ dependencies = [
[[package]]
name = "atomic-write-file"
version = "0.1.2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436"
checksum = "a8204db279bf648d64fe845bd8840f78b39c8132ed4d6a4194c3b10d4b4cfb0b"
dependencies = [
"nix 0.27.1",
"nix 0.28.0",
"rand",
]
@ -739,7 +739,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
dependencies = [
"memchr",
"regex-automata 0.4.5",
"regex-automata 0.4.6",
"serde",
]
@ -846,10 +846,11 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.88"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc"
checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723"
dependencies = [
"jobserver",
"libc",
]
@ -1065,9 +1066,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "const-random"
version = "0.1.17"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
@ -2253,9 +2254,9 @@ dependencies = [
[[package]]
name = "http"
version = "0.2.11"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
dependencies = [
"bytes",
"fnv",
@ -2687,9 +2688,9 @@ dependencies = [
[[package]]
name = "insta"
version = "1.35.1"
version = "1.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c985c1bef99cf13c58fade470483d81a2bfe846ebde60ed28cc2dddec2df9e2"
checksum = "0a7c22c4d34ef4788c351e971c52bfdfe7ea2766f8c5466bc175dd46e52ac22e"
dependencies = [
"console",
"lazy_static",
@ -2938,10 +2939,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "js-sys"
version = "0.3.68"
name = "jobserver"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
dependencies = [
"wasm-bindgen",
]
@ -3117,7 +3127,7 @@ version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553"
dependencies = [
"regex-automata 0.4.5",
"regex-automata 0.4.6",
]
[[package]]
@ -3360,9 +3370,9 @@ dependencies = [
[[package]]
name = "mio"
version = "0.8.10"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"log",
@ -3999,9 +4009,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pest"
version = "2.7.7"
version = "2.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546"
checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8"
dependencies = [
"memchr",
"thiserror",
@ -4010,9 +4020,9 @@ dependencies = [
[[package]]
name = "pest_derive"
version = "2.7.7"
version = "2.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809"
checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026"
dependencies = [
"pest",
"pest_generator",
@ -4020,9 +4030,9 @@ dependencies = [
[[package]]
name = "pest_generator"
version = "2.7.7"
version = "2.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e"
checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80"
dependencies = [
"pest",
"pest_meta",
@ -4033,9 +4043,9 @@ dependencies = [
[[package]]
name = "pest_meta"
version = "2.7.7"
version = "2.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a"
checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293"
dependencies = [
"once_cell",
"pest",
@ -4552,7 +4562,7 @@ checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata 0.4.5",
"regex-automata 0.4.6",
"regex-syntax 0.8.2",
]
@ -4567,9 +4577,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.5"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
dependencies = [
"aho-corasick",
"memchr",
@ -5609,9 +5619,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "sysinfo"
version = "0.30.5"
version = "0.30.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2"
checksum = "6746919caf9f2a85bff759535664c060109f21975c5ac2e8652e60102bd4d196"
dependencies = [
"cfg-if",
"core-foundation-sys",
@ -6429,9 +6439,9 @@ dependencies = [
[[package]]
name = "walkdir"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
@ -6453,10 +6463,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.91"
name = "wasite"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
[[package]]
name = "wasm-bindgen"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@ -6464,9 +6480,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.91"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
dependencies = [
"bumpalo",
"log",
@ -6479,9 +6495,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.41"
version = "0.4.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
dependencies = [
"cfg-if",
"js-sys",
@ -6491,9 +6507,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.91"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -6501,9 +6517,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.91"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
@ -6514,9 +6530,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.91"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "wasm-streams"
@ -6533,9 +6549,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.68"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -6561,9 +6577,13 @@ dependencies = [
[[package]]
name = "whoami"
version = "1.4.1"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50"
checksum = "0fec781d48b41f8163426ed18e8fc2864c12937df9ce54c88ede7bd47270893e"
dependencies = [
"redox_syscall",
"wasite",
]
[[package]]
name = "winapi"
@ -6823,7 +6843,7 @@ dependencies = [
"rand",
"rand_core",
"regex",
"regex-automata 0.4.5",
"regex-automata 0.4.6",
"regex-syntax 0.8.2",
"reqwest",
"ring",

View File

@ -1,19 +1,24 @@
use std::collections::HashSet;
use influxdb_influxql_parser::{
common::ParseError, identifier::Identifier, parse_statements as parse_internal,
select::MeasurementSelection, show_measurements::ExtendedOnClause, statement::Statement,
common::ParseError,
explain::ExplainStatement,
identifier::Identifier,
parse_statements as parse_internal,
select::{MeasurementSelection, SelectStatement},
show_measurements::ExtendedOnClause,
statement::Statement,
};
#[derive(Debug)]
pub struct RewrittenStatement {
pub struct Rewritten<S> {
database: Option<Identifier>,
retention_policy: Option<Identifier>,
statement: Statement,
statement: S,
}
impl RewrittenStatement {
fn new(statement: Statement) -> Self {
impl<S> Rewritten<S> {
fn new(statement: S) -> Self {
Self {
database: None,
retention_policy: None,
@ -39,11 +44,11 @@ impl RewrittenStatement {
self.retention_policy.as_ref()
}
pub fn statement(&self) -> &Statement {
pub fn statement(&self) -> &S {
&self.statement
}
pub fn to_statement(self) -> Statement {
pub fn to_statement(self) -> S {
self.statement
}
@ -62,13 +67,13 @@ impl RewrittenStatement {
}
}
impl From<RewrittenStatement> for Statement {
fn from(r: RewrittenStatement) -> Self {
impl From<Rewritten<Statement>> for Statement {
fn from(r: Rewritten<Statement>) -> Self {
r.to_statement()
}
}
impl TryFrom<Statement> for RewrittenStatement {
impl TryFrom<Statement> for Rewritten<Statement> {
type Error = Error;
fn try_from(statement: Statement) -> Result<Self, Self::Error> {
@ -106,42 +111,83 @@ impl TryFrom<Statement> for RewrittenStatement {
let identifier = s.database.take().map(Into::into);
Ok(Self::new(Statement::ShowFieldKeys(s)).with_database(identifier))
}
Statement::Select(mut s) => {
let mut db_rp_set = HashSet::new();
let from_clause = s
.from
.take()
.into_iter()
.map(|ms| match ms {
MeasurementSelection::Name(mut qn) => {
let db = qn.database.take();
let rp = qn.retention_policy.take();
if db_rp_set.insert((db, rp)) && db_rp_set.len() > 1 {
return Err(Error::MultiDatabase);
}
Ok(MeasurementSelection::Name(qn))
}
// TODO - handle sub-queries?
MeasurementSelection::Subquery(_) => Ok(ms),
})
.collect::<Result<Vec<MeasurementSelection>, Error>>()?;
s.from.replace(from_clause);
let mut result = Self::new(Statement::Select(s));
if let Some((db, rp)) = db_rp_set.into_iter().next() {
result = result.with_database(db).with_retention_policy(rp);
}
Ok(result)
Statement::Select(s) => {
let ss = Rewritten::<SelectStatement>::try_from(*s)?;
let db = ss.database.to_owned();
let rp = ss.retention_policy.to_owned();
Ok(Self::new(Statement::Select(Box::new(ss.to_statement())))
.with_database(db)
.with_retention_policy(rp))
}
Statement::Explain(mut s) => {
let options = s.options.take();
let s = Self::try_from(*s.statement)?;
let db = s.database.to_owned();
let rp = s.retention_policy.to_owned();
Ok(Self::new(Statement::Explain(Box::new(ExplainStatement {
options,
statement: Box::new(s.to_statement()),
})))
.with_database(db)
.with_retention_policy(rp))
}
// For all other statements, we just pass them through. Explicitly
// do not use a catch-all match arm here in the event that new variants
// are added to the Statement enum, we want the compiler to direct us
// here to handle, if relevant.
Statement::CreateDatabase(_)
| Statement::Delete(_)
| Statement::DropMeasurement(_)
| Statement::Explain(_)
| Statement::ShowDatabases(_) => Ok(Self::new(statement)),
}
}
}
#[derive(Debug, thiserror::Error, Clone)]
impl TryFrom<SelectStatement> for Rewritten<SelectStatement> {
type Error = Error;
fn try_from(mut select_statement: SelectStatement) -> Result<Self, Self::Error> {
let mut db_rp_set = HashSet::new();
let from_clause = select_statement
.from
.take()
.into_iter()
.map(|ms| {
let (db, rp, ms) = match ms {
MeasurementSelection::Name(mut qn) => {
let db = qn.database.take();
let rp = qn.retention_policy.take();
(db, rp, MeasurementSelection::Name(qn))
}
// Recursively call try_from on nested sub-queries, and compare their
// resulting db/rp to the same at this level. Sub-queries that have
// multiple db/rp in them will throw the MultiDatabase error.
MeasurementSelection::Subquery(s) => {
let ss = Self::try_from(*s)?;
(
ss.database.to_owned(),
ss.retention_policy.to_owned(),
MeasurementSelection::Subquery(Box::new(ss.to_statement())),
)
}
};
if db_rp_set.insert((db, rp)) && db_rp_set.len() > 1 {
Err(Error::MultiDatabase)
} else {
Ok(ms)
}
})
.collect::<Result<Vec<MeasurementSelection>, Error>>()?;
select_statement.from.replace(from_clause);
let mut result = Self::new(select_statement);
if let Some((db, rp)) = db_rp_set.into_iter().next() {
result = result.with_database(db).with_retention_policy(rp);
}
Ok(result)
}
}
#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
pub enum Error {
#[error("can only perform queries on a single database")]
MultiDatabase,
@ -149,10 +195,361 @@ pub enum Error {
Parse(ParseError),
}
pub fn parse_statements(input: &str) -> Result<Vec<RewrittenStatement>, Error> {
pub fn parse_statements(input: &str) -> Result<Vec<Rewritten<Statement>>, Error> {
parse_internal(input)
.map_err(Error::Parse)?
.into_iter()
.map(RewrittenStatement::try_from)
.collect::<Result<Vec<RewrittenStatement>, Error>>()
.map(Rewritten::<Statement>::try_from)
.collect::<Result<Vec<Rewritten<Statement>>, Error>>()
}
#[cfg(test)]
mod tests {
use influxdb_influxql_parser::statement::Statement;
use crate::{parse_statements, Error, Rewritten};
fn parse_single(input: &str) -> Rewritten<Statement> {
parse_statements(input).unwrap().pop().unwrap()
}
fn parse_single_failure(input: &str) -> Error {
parse_statements(input).unwrap_err()
}
struct TestCase {
input: &'static str,
expected: &'static str,
db: Option<&'static str>,
rp: Option<&'static str>,
}
impl TestCase {
fn assert(&self) {
let s = parse_single(self.input);
assert_eq!(s.database().map(|db| db.as_str()), self.db);
assert_eq!(s.retention_policy().map(|rp| rp.as_str()), self.rp);
assert_eq!(self.expected, s.to_statement().to_string());
}
}
struct TestFailure {
input: &'static str,
expected: Error,
}
impl TestFailure {
fn assert(&self) {
let e = parse_single_failure(self.input);
assert_eq!(self.expected, e, "input: {}", self.input);
}
}
#[test]
fn show_measurements() {
TestCase {
input: "SHOW MEASUREMENTS",
expected: "SHOW MEASUREMENTS",
db: None,
rp: None,
}
.assert();
TestCase {
input: "SHOW MEASUREMENTS ON foo",
expected: "SHOW MEASUREMENTS",
db: Some("foo"),
rp: None,
}
.assert();
TestCase {
input: "SHOW MEASUREMENTS ON foo.bar",
expected: "SHOW MEASUREMENTS",
db: Some("foo"),
rp: Some("bar"),
}
.assert();
}
#[test]
fn show_measurements_failure_modes() {
TestFailure {
input: "SHOW MEASUREMENTS ON *.*",
expected: Error::MultiDatabase,
}
.assert();
TestFailure {
input: r#"SHOW MEASUREMENTS ON *"#,
expected: Error::MultiDatabase,
}
.assert();
}
#[test]
fn show_retention_policies() {
TestCase {
input: "SHOW RETENTION POLICIES",
expected: "SHOW RETENTION POLICIES",
db: None,
rp: None,
}
.assert();
TestCase {
input: "SHOW RETENTION POLICIES ON foo",
expected: "SHOW RETENTION POLICIES",
db: Some("foo"),
rp: None,
}
.assert();
}
#[test]
fn show_tag_keys() {
TestCase {
input: "SHOW TAG KEYS",
expected: "SHOW TAG KEYS",
db: None,
rp: None,
}
.assert();
TestCase {
input: "SHOW TAG KEYS FROM cpu",
expected: "SHOW TAG KEYS FROM cpu",
db: None,
rp: None,
}
.assert();
TestCase {
input: "SHOW TAG KEYS ON foo",
expected: "SHOW TAG KEYS",
db: Some("foo"),
rp: None,
}
.assert();
TestCase {
input: "SHOW TAG KEYS ON foo FROM cpu",
expected: "SHOW TAG KEYS FROM cpu",
db: Some("foo"),
rp: None,
}
.assert();
}
#[test]
fn show_tag_values() {
TestCase {
input: "SHOW TAG VALUES WITH KEY = host",
expected: "SHOW TAG VALUES WITH KEY = host",
db: None,
rp: None,
}
.assert();
TestCase {
input: "SHOW TAG VALUES FROM cpu WITH KEY = host",
expected: "SHOW TAG VALUES FROM cpu WITH KEY = host",
db: None,
rp: None,
}
.assert();
TestCase {
input: "SHOW TAG VALUES ON foo WITH KEY = host",
expected: "SHOW TAG VALUES WITH KEY = host",
db: Some("foo"),
rp: None,
}
.assert();
TestCase {
input: "SHOW TAG VALUES ON foo FROM cpu WITH KEY = host",
expected: "SHOW TAG VALUES FROM cpu WITH KEY = host",
db: Some("foo"),
rp: None,
}
.assert();
}
#[test]
fn show_field_keys() {
TestCase {
input: "SHOW FIELD KEYS",
expected: "SHOW FIELD KEYS",
db: None,
rp: None,
}
.assert();
TestCase {
input: "SHOW FIELD KEYS FROM cpu",
expected: "SHOW FIELD KEYS FROM cpu",
db: None,
rp: None,
}
.assert();
TestCase {
input: "SHOW FIELD KEYS ON foo",
expected: "SHOW FIELD KEYS",
db: Some("foo"),
rp: None,
}
.assert();
TestCase {
input: "SHOW FIELD KEYS ON foo FROM cpu",
expected: "SHOW FIELD KEYS FROM cpu",
db: Some("foo"),
rp: None,
}
.assert();
}
#[test]
fn select() {
TestCase {
input: "SELECT * FROM cpu",
expected: "SELECT * FROM cpu",
db: None,
rp: None,
}
.assert();
TestCase {
input: "SELECT * FROM bar.cpu",
expected: "SELECT * FROM cpu",
db: None,
rp: Some("bar"),
}
.assert();
TestCase {
input: "SELECT * FROM foo.bar.cpu",
expected: "SELECT * FROM cpu",
db: Some("foo"),
rp: Some("bar"),
}
.assert();
TestCase {
input: r#"SELECT * FROM (SELECT * FROM cpu)"#,
expected: r#"SELECT * FROM (SELECT * FROM cpu)"#,
db: None,
rp: None,
}
.assert();
TestCase {
input: r#"SELECT * FROM (SELECT * FROM bar.cpu), bar.mem"#,
expected: r#"SELECT * FROM (SELECT * FROM cpu), mem"#,
db: None,
rp: Some("bar"),
}
.assert();
TestCase {
input: r#"SELECT * FROM (SELECT * FROM foo.bar.cpu), foo.bar.mem"#,
expected: r#"SELECT * FROM (SELECT * FROM cpu), mem"#,
db: Some("foo"),
rp: Some("bar"),
}
.assert();
}
#[test]
fn select_failure_modes() {
TestFailure {
input: r#"SELECT * FROM foo.bar.cpu, baz.bop.cpu"#,
expected: Error::MultiDatabase,
}
.assert();
TestFailure {
input: r#"SELECT * FROM cpu, baz.bop.cpu"#,
expected: Error::MultiDatabase,
}
.assert();
TestFailure {
input: r#"SELECT * FROM bar.cpu, baz.bop.cpu"#,
expected: Error::MultiDatabase,
}
.assert();
TestFailure {
input: r#"SELECT * FROM foo.bar.cpu, (SELECT * FROM mem)"#,
expected: Error::MultiDatabase,
}
.assert();
}
#[test]
fn explain() {
TestCase {
input: "EXPLAIN SELECT * FROM cpu",
expected: "EXPLAIN SELECT * FROM cpu",
db: None,
rp: None,
}
.assert();
TestCase {
input: "EXPLAIN SELECT * FROM bar.cpu",
expected: "EXPLAIN SELECT * FROM cpu",
db: None,
rp: Some("bar"),
}
.assert();
TestCase {
input: "EXPLAIN SELECT * FROM foo.bar.cpu",
expected: "EXPLAIN SELECT * FROM cpu",
db: Some("foo"),
rp: Some("bar"),
}
.assert();
TestCase {
input: r#"EXPLAIN SELECT * FROM (SELECT * FROM cpu)"#,
expected: r#"EXPLAIN SELECT * FROM (SELECT * FROM cpu)"#,
db: None,
rp: None,
}
.assert();
TestCase {
input: r#"EXPLAIN SELECT * FROM (SELECT * FROM bar.cpu), bar.mem"#,
expected: r#"EXPLAIN SELECT * FROM (SELECT * FROM cpu), mem"#,
db: None,
rp: Some("bar"),
}
.assert();
TestCase {
input: r#"EXPLAIN SELECT * FROM (SELECT * FROM foo.bar.cpu), foo.bar.mem"#,
expected: r#"EXPLAIN SELECT * FROM (SELECT * FROM cpu), mem"#,
db: Some("foo"),
rp: Some("bar"),
}
.assert();
}
#[test]
fn noop_rewrites() {
TestCase {
input: "CREATE DATABASE foo",
expected: "CREATE DATABASE foo",
db: None,
rp: None,
}
.assert();
TestCase {
input: "DELETE FROM cpu",
expected: "DELETE FROM cpu",
db: None,
rp: None,
}
.assert();
TestCase {
input: "DROP MEASUREMENT cpu",
expected: "DROP MEASUREMENT cpu",
db: None,
rp: None,
}
.assert();
TestCase {
input: "EXPLAIN SELECT * FROM cpu",
expected: "EXPLAIN SELECT * FROM cpu",
db: None,
rp: None,
}
.assert();
TestCase {
input: "SHOW DATABASES",
expected: "SHOW DATABASES",
db: None,
rp: None,
}
.assert();
}
}