From b9fb3ca59fda99997a51cab7a56d34fb2126dd08 Mon Sep 17 00:00:00 2001 From: Jiacai Liu Date: Sun, 4 Feb 2024 16:19:46 +0800 Subject: [PATCH] chore: bump datafusion (#14) Co-authored-by: Ruixiang Tan --- Cargo.lock | 546 ++++++++---------- Cargo.toml | 5 +- arrow_util/Cargo.toml | 3 +- arrow_util/src/display.rs | 2 +- arrow_util/src/test_util.rs | 6 +- datafusion_util/src/lib.rs | 4 +- influxdb_influxql_parser/src/string.rs | 18 +- iox_query/src/exec/gapfill/algo.rs | 44 +- .../src/exec/gapfill/algo/interpolate.rs | 12 +- iox_query/src/exec/gapfill/exec_tests.rs | 56 +- iox_query/src/exec/gapfill/mod.rs | 4 +- iox_query/src/exec/gapfill/stream.rs | 8 +- iox_query/src/exec/non_null_checker.rs | 4 +- iox_query/src/exec/schema_pivot.rs | 4 +- iox_query/src/exec/split.rs | 10 +- .../src/logical_optimizer/handle_gapfill.rs | 59 +- .../handle_gapfill/range_predicate.rs | 11 +- .../influx_regex_to_datafusion_regex.rs | 16 +- iox_query_influxql/src/frontend/planner.rs | 2 +- iox_query_influxql/src/plan/planner.rs | 465 ++++++++------- .../src/plan/planner_time_range_expression.rs | 4 +- iox_query_influxql/src/plan/rewriter.rs | 8 +- iox_query_influxql/src/plan/timestamp.rs | 4 +- iox_query_influxql/src/plan/util_copy.rs | 44 +- query_functions/src/regex.rs | 28 +- query_functions/src/selectors/internal.rs | 4 +- query_functions/src/window/internal.rs | 8 +- rust-toolchain | 2 +- test_helpers/Cargo.toml | 2 +- test_helpers/src/timeout.rs | 4 +- 30 files changed, 681 insertions(+), 706 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8a35fa..55dc302 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "ahash" version = "0.8.3" @@ -30,21 +24,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - [[package]] name = "allocator-api2" version = "0.2.15" @@ -72,11 +51,23 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "arrow" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2feeebd77b34b0bc88f224e06d01c27da4733997cc4789a4e056196656cdc59a" +checksum = "5bc25126d18a012146a888a0298f2c22e1150327bd2765fc76d710a556b2d614" dependencies = [ "ahash", "arrow-arith", @@ -96,9 +87,9 @@ dependencies = [ [[package]] name = "arrow-arith" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7173f5dc49c0ecb5135f52565af33afd3fdc9a12d13bd6f9973e8b96305e4b2e" +checksum = "34ccd45e217ffa6e53bbb0080990e77113bdd4e91ddb84e97b77649810bcf1a7" dependencies = [ "arrow-array", "arrow-buffer", @@ -111,9 +102,9 @@ dependencies = [ [[package]] name = "arrow-array" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d7ea725f7d1f8bb2cffc53ef538557e95fc802e217d5be25122d402e22f3d0" +checksum = "6bda9acea48b25123c08340f3a8ac361aa0f74469bb36f5ee9acf923fce23e9d" dependencies = [ "ahash", "arrow-buffer", @@ -128,25 +119,27 @@ dependencies = [ [[package]] name = "arrow-buffer" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbe439e077f484e5000b9e1d47b5e4c0d15f2b311a8f5bcc682553d5d67a722" +checksum = "01a0fc21915b00fc6c2667b069c1b64bdd920982f426079bc4a7cab86822886c" dependencies = [ + "bytes", "half", "num", ] [[package]] name = "arrow-cast" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93913cc14875770aa1eef5e310765e855effa352c094cb1c7c00607d0f37b4e1" +checksum = "5dc0368ed618d509636c1e3cc20db1281148190a78f43519487b2daf07b63b4a" dependencies = [ "arrow-array", "arrow-buffer", "arrow-data", "arrow-schema", "arrow-select", + "base64 0.21.2", "chrono", "comfy-table 7.0.1", "half", @@ -156,9 +149,9 @@ dependencies = [ [[package]] name = "arrow-csv" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef55b67c55ed877e6fe7b923121c19dae5e31ca70249ea2779a17b58fb0fbd9a" +checksum = "2e09aa6246a1d6459b3f14baeaa49606cfdbca34435c46320e14054d244987ca" dependencies = [ "arrow-array", "arrow-buffer", @@ -175,9 +168,9 @@ dependencies = [ [[package]] name = "arrow-data" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4f4f4a3c54614126a71ab91f6631c9743eb4643d6e9318b74191da9dc6e028b" +checksum = "907fafe280a3874474678c1858b9ca4cb7fd83fb8034ff5b6d6376205a08c634" dependencies = [ "arrow-buffer", "arrow-schema", @@ -187,9 +180,9 @@ dependencies = [ [[package]] name = "arrow-ipc" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d41a3659f984a524ef1c2981d43747b24d8eec78e2425267fcd0ef34ce71cd18" +checksum = "79a43d6808411886b8c7d4f6f7dd477029c1e77ffffffb7923555cc6579639cd" dependencies = [ "arrow-array", "arrow-buffer", @@ -201,9 +194,9 @@ dependencies = [ [[package]] name = "arrow-json" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b95faa95a378f56ef32d84cc0104ea998c39ef7cd1faaa6b4cebf8ea92846d" +checksum = "d82565c91fd627922ebfe2810ee4e8346841b6f9361b87505a9acea38b614fee" dependencies = [ "arrow-array", "arrow-buffer", @@ -221,9 +214,9 @@ dependencies = [ [[package]] name = "arrow-ord" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68549a4284d9f8b39586afb8d5ff8158b8f0286353a4844deb1d11cf1ba1f26" +checksum = "9b23b0e53c0db57c6749997fd343d4c0354c994be7eca67152dd2bdb9a3e1bb4" dependencies = [ "arrow-array", "arrow-buffer", @@ -236,9 +229,9 @@ dependencies = [ [[package]] name = "arrow-row" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a75a4a757afc301ce010adadff54d79d66140c4282ed3de565f6ccb716a5cf3" +checksum = "361249898d2d6d4a6eeb7484be6ac74977e48da12a4dd81a708d620cc558117a" dependencies = [ "ahash", "arrow-array", @@ -251,16 +244,17 @@ dependencies = [ [[package]] name = "arrow-schema" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bebcb57eef570b15afbcf2d07d813eb476fde9f6dd69c81004d6476c197e87e" +checksum = "09e28a5e781bf1b0f981333684ad13f5901f4cd2f20589eab7cf1797da8fc167" [[package]] name = "arrow-select" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e2943fa433a48921e914417173816af64eef61c0a3d448280e6c40a62df221" +checksum = "4f6208466590960efc1d2a7172bc4ff18a67d6e25c529381d7f96ddaf0dc4036" dependencies = [ + "ahash", "arrow-array", "arrow-buffer", "arrow-data", @@ -270,9 +264,9 @@ dependencies = [ [[package]] name = "arrow-string" -version = "43.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc92ed638851774f6d7af1ad900b92bc1486746497511868b4298fcbcfa35af" +checksum = "a4a48149c63c11c9ff571e50ab8f017d2a7cb71037a882b42f6354ed2da9acc7" dependencies = [ "arrow-array", "arrow-buffer", @@ -281,7 +275,7 @@ dependencies = [ "arrow-select", "num", "regex", - "regex-syntax 0.7.2", + "regex-syntax 0.8.2", ] [[package]] @@ -310,13 +304,13 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -344,37 +338,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "brotli" -version = "3.3.4" +name = "blake2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", + "digest", ] [[package]] -name = "brotli-decompressor" -version = "2.3.4" +name = "blake3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", ] [[package]] -name = "bumpalo" -version = "3.13.0" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] [[package]] -name = "byteorder" -version = "1.4.3" +name = "bumpalo" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytes" @@ -387,9 +385,6 @@ name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" -dependencies = [ - "jobserver", -] [[package]] name = "cfg-if" @@ -399,14 +394,14 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "winapi", + "windows-targets 0.48.0", ] [[package]] @@ -487,6 +482,12 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -494,12 +495,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] -name = "crc32fast" -version = "1.3.2" +name = "cpufeatures" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ - "cfg-if", + "libc", ] [[package]] @@ -508,6 +509,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "csv" version = "1.2.2" @@ -544,8 +555,8 @@ dependencies = [ [[package]] name = "datafusion" -version = "27.0.0" -source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=9c3a537e25e5ab3299922864034f67fb2f79805d#9c3a537e25e5ab3299922864034f67fb2f79805d" +version = "33.0.0" +source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=e21b03154#e21b03154511cd61e03e299a595db6be6b1852c1" dependencies = [ "ahash", "arrow", @@ -560,23 +571,20 @@ dependencies = [ "datafusion-expr", "datafusion-optimizer", "datafusion-physical-expr", - "datafusion-row", + "datafusion-physical-plan", "datafusion-sql", "futures", "glob", + "half", "hashbrown 0.14.0", "indexmap 2.0.0", - "itertools 0.11.0", - "lazy_static", + "itertools 0.12.0", "log", "num_cpus", "object_store", "parking_lot", - "parquet", - "percent-encoding", "pin-project-lite", "rand", - "smallvec", "sqlparser", "tempfile", "tokio", @@ -587,26 +595,33 @@ dependencies = [ [[package]] name = "datafusion-common" -version = "27.0.0" -source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=9c3a537e25e5ab3299922864034f67fb2f79805d#9c3a537e25e5ab3299922864034f67fb2f79805d" +version = "33.0.0" +source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=e21b03154#e21b03154511cd61e03e299a595db6be6b1852c1" dependencies = [ + "ahash", "arrow", "arrow-array", + "arrow-buffer", + "arrow-schema", "chrono", + "half", + "libc", "num_cpus", "object_store", - "parquet", "sqlparser", ] [[package]] name = "datafusion-execution" -version = "27.0.0" -source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=9c3a537e25e5ab3299922864034f67fb2f79805d#9c3a537e25e5ab3299922864034f67fb2f79805d" +version = "33.0.0" +source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=e21b03154#e21b03154511cd61e03e299a595db6be6b1852c1" dependencies = [ + "arrow", + "chrono", "dashmap", "datafusion-common", "datafusion-expr", + "futures", "hashbrown 0.14.0", "log", "object_store", @@ -618,13 +633,14 @@ dependencies = [ [[package]] name = "datafusion-expr" -version = "27.0.0" -source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=9c3a537e25e5ab3299922864034f67fb2f79805d#9c3a537e25e5ab3299922864034f67fb2f79805d" +version = "33.0.0" +source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=e21b03154#e21b03154511cd61e03e299a595db6be6b1852c1" dependencies = [ "ahash", "arrow", + "arrow-array", "datafusion-common", - "lazy_static", + "paste", "sqlparser", "strum 0.25.0", "strum_macros 0.25.1", @@ -632,8 +648,8 @@ dependencies = [ [[package]] name = "datafusion-optimizer" -version = "27.0.0" -source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=9c3a537e25e5ab3299922864034f67fb2f79805d#9c3a537e25e5ab3299922864034f67fb2f79805d" +version = "33.0.0" +source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=e21b03154#e21b03154511cd61e03e299a595db6be6b1852c1" dependencies = [ "arrow", "async-trait", @@ -642,53 +658,78 @@ dependencies = [ "datafusion-expr", "datafusion-physical-expr", "hashbrown 0.14.0", - "itertools 0.11.0", + "itertools 0.12.0", "log", - "regex-syntax 0.7.2", + "regex-syntax 0.8.2", ] [[package]] name = "datafusion-physical-expr" -version = "27.0.0" -source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=9c3a537e25e5ab3299922864034f67fb2f79805d#9c3a537e25e5ab3299922864034f67fb2f79805d" +version = "33.0.0" +source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=e21b03154#e21b03154511cd61e03e299a595db6be6b1852c1" dependencies = [ "ahash", "arrow", "arrow-array", "arrow-buffer", + "arrow-ord", "arrow-schema", + "base64 0.21.2", + "blake2", + "blake3", "chrono", "datafusion-common", "datafusion-expr", - "datafusion-row", "half", "hashbrown 0.14.0", + "hex", "indexmap 2.0.0", - "itertools 0.11.0", - "lazy_static", - "libc", + "itertools 0.12.0", "log", + "md-5", "paste", "petgraph", "rand", + "regex", + "sha2", + "unicode-segmentation", "uuid", ] [[package]] -name = "datafusion-row" -version = "27.0.0" -source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=9c3a537e25e5ab3299922864034f67fb2f79805d#9c3a537e25e5ab3299922864034f67fb2f79805d" +name = "datafusion-physical-plan" +version = "33.0.0" +source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=e21b03154#e21b03154511cd61e03e299a595db6be6b1852c1" dependencies = [ + "ahash", "arrow", + "arrow-array", + "arrow-buffer", + "arrow-schema", + "async-trait", + "chrono", "datafusion-common", - "paste", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr", + "futures", + "half", + "hashbrown 0.14.0", + "indexmap 2.0.0", + "itertools 0.12.0", + "log", + "once_cell", + "parking_lot", + "pin-project-lite", "rand", + "tokio", + "uuid", ] [[package]] name = "datafusion-sql" -version = "27.0.0" -source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=9c3a537e25e5ab3299922864034f67fb2f79805d#9c3a537e25e5ab3299922864034f67fb2f79805d" +version = "33.0.0" +source = "git+https://github.com/CeresDB/arrow-datafusion.git?rev=e21b03154#e21b03154511cd61e03e299a595db6be6b1852c1" dependencies = [ "arrow", "arrow-schema", @@ -712,6 +753,17 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "doc-comment" version = "0.3.3" @@ -788,16 +840,6 @@ dependencies = [ "rustc_version", ] -[[package]] -name = "flate2" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "form_urlencoded" version = "1.2.0" @@ -863,7 +905,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -909,6 +951,16 @@ dependencies = [ "tonic-build", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -982,6 +1034,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "humantime" version = "2.1.0" @@ -1079,12 +1137,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "integer-encoding" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" - [[package]] name = "io-lifetimes" version = "1.0.11" @@ -1164,19 +1216,19 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "1.0.6" +name = "itertools" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] [[package]] -name = "jobserver" -version = "0.1.26" +name = "itoa" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" -dependencies = [ - "libc", -] +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" @@ -1298,32 +1350,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] -name = "lz4" -version = "1.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" -dependencies = [ - "libc", - "lz4-sys", -] - -[[package]] -name = "lz4-sys" -version = "1.9.4" +name = "matchers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "cc", - "libc", + "regex-automata", ] [[package]] -name = "matchers" -version = "0.1.0" +name = "md-5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "regex-automata", + "cfg-if", + "digest", ] [[package]] @@ -1338,15 +1380,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - [[package]] name = "multimap" version = "0.8.3" @@ -1375,9 +1408,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ "num-bigint", "num-complex", @@ -1462,16 +1495,16 @@ dependencies = [ [[package]] name = "object_store" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c776db4f332b571958444982ff641d2531417a326ca368995073b639205d58" +checksum = "2524735495ea1268be33d200e1ee97455096a0846295a21548cd2f3541de7050" dependencies = [ "async-trait", "bytes", "chrono", "futures", "humantime", - "itertools 0.10.5", + "itertools 0.11.0", "parking_lot", "percent-encoding", "snafu", @@ -1497,15 +1530,6 @@ dependencies = [ "parking_lot_core", ] -[[package]] -name = "ordered-float" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" -dependencies = [ - "num-traits", -] - [[package]] name = "overload" version = "0.1.1" @@ -1535,40 +1559,6 @@ dependencies = [ "windows-targets 0.48.0", ] -[[package]] -name = "parquet" -version = "43.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7267a9607c3f955d4d0ac41b88a67cecc0d8d009173ad3da390699a6cb3750" -dependencies = [ - "ahash", - "arrow-array", - "arrow-buffer", - "arrow-cast", - "arrow-data", - "arrow-ipc", - "arrow-schema", - "arrow-select", - "base64 0.21.2", - "brotli", - "bytes", - "chrono", - "flate2", - "futures", - "hashbrown 0.14.0", - "lz4", - "num", - "num-bigint", - "object_store", - "paste", - "seq-macro", - "snap", - "thrift", - "tokio", - "twox-hash", - "zstd", -] - [[package]] name = "parse-zoneinfo" version = "0.3.0" @@ -1692,7 +1682,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -1707,12 +1697,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1737,9 +1721,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c" dependencies = [ "unicode-ident", ] @@ -1818,9 +1802,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1896,6 +1880,12 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1964,12 +1954,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" -[[package]] -name = "seq-macro" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b44e8fc93a14e66336d230954dda83d18b4605ccace8fe09bc7514a71ad0bc" - [[package]] name = "serde" version = "1.0.164" @@ -1987,7 +1971,7 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -2001,6 +1985,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -2059,17 +2054,11 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "snap" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" - [[package]] name = "sqlparser" -version = "0.35.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca597d77c98894be1f965f2e4e2d2a61575d4998088e655476c73715c54b2b43" +checksum = "743b4dc2cbde11890ccb254a8fc9d537fa41b36da00de2a1c5e9848c9bc42bd7" dependencies = [ "log", "sqlparser_derive", @@ -2130,9 +2119,15 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.22", + "syn 2.0.38", ] +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -2146,9 +2141,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.22" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -2193,17 +2188,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "thrift" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e54bc85fc7faa8bc175c4bab5b92ba8d9a3ce893d0e9f42cc455c8ab16a9e09" -dependencies = [ - "byteorder", - "integer-encoding", - "ordered-float", -] - [[package]] name = "tiny-keccak" version = "2.0.2" @@ -2251,7 +2235,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -2311,7 +2295,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -2354,14 +2338,10 @@ dependencies = [ ] [[package]] -name = "twox-hash" -version = "1.6.3" +name = "typenum" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "static_assertions", -] +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" @@ -2384,6 +2364,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-width" version = "0.1.10" @@ -2459,7 +2445,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -2481,7 +2467,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2683,33 +2669,3 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] - -[[package]] -name = "zstd" -version = "0.12.3+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "6.0.5+zstd.1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" -dependencies = [ - "cc", - "libc", - "pkg-config", -] diff --git a/Cargo.toml b/Cargo.toml index 66ac3b2..0b3c8af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = ["datafusion_util", "influxdb_influxql_parser", "iox_query_influxql", "observability_deps", "schema", "test_helpers"] +resolver = "2" [workspace.package] version = "0.1.0" @@ -8,6 +9,6 @@ edition = "2021" license = "MIT OR Apache-2.0" [workspace.dependencies] -arrow = { version = "43.0.0" } -datafusion = { git = "https://github.com/CeresDB/arrow-datafusion.git", rev = "9c3a537e25e5ab3299922864034f67fb2f79805d", default-features = false } +arrow = { version = "49.0.0" } +datafusion = { git = "https://github.com/CeresDB/arrow-datafusion.git", rev = "e21b03154", default-features = false } hashbrown = { version = "0.13.2" } diff --git a/arrow_util/Cargo.toml b/arrow_util/Cargo.toml index 2202bd4..89b8897 100644 --- a/arrow_util/Cargo.toml +++ b/arrow_util/Cargo.toml @@ -8,8 +8,7 @@ license.workspace = true [dependencies] ahash = { version = "0.8", default-features = false, features = ["runtime-rng"] } -# need dyn_cmp_dict feature for comparing dictionary arrays -arrow = { workspace = true, features = ["prettyprint", "dyn_cmp_dict"] } +arrow = { workspace = true, features = ["prettyprint"] } # used by arrow anyway (needed for printing workaround) chrono = { version = "0.4", default-features = false } comfy-table = { version = "6.1", default-features = false } diff --git a/arrow_util/src/display.rs b/arrow_util/src/display.rs index d723d12..cba4b91 100644 --- a/arrow_util/src/display.rs +++ b/arrow_util/src/display.rs @@ -40,7 +40,7 @@ fn array_value_to_string(column: &ArrayRef, row: usize) -> Result { ) })?; // treat as UTC - let ts = DateTime::::from_utc(ts, Utc); + let ts = DateTime::::from_naive_utc_and_offset(ts, Utc); // convert to string in preferred influx format let use_z = true; Ok(ts.to_rfc3339_opts(SecondsFormat::AutoSi, use_z)) diff --git a/arrow_util/src/test_util.rs b/arrow_util/src/test_util.rs index a8cbd04..ec5b0c9 100644 --- a/arrow_util/src/test_util.rs +++ b/arrow_util/src/test_util.rs @@ -221,15 +221,15 @@ static REGEX_LINESEP: Lazy = Lazy::new(|| Regex::new(r#"[+-]{6,}"#).expec /// /// ` |` -> ` |` /// ` |` -> ` |` -static REGEX_COL: Lazy = Lazy::new(|| Regex::new(r#"\s+\|"#).expect("col regex")); +static REGEX_COL: Lazy = Lazy::new(|| Regex::new(r"\s+\|").expect("col regex")); /// Matches line like `metrics=[foo=1, bar=2]` static REGEX_METRICS: Lazy = - Lazy::new(|| Regex::new(r#"metrics=\[([^\]]*)\]"#).expect("metrics regex")); + Lazy::new(|| Regex::new(r"metrics=\[([^\]]*)\]").expect("metrics regex")); /// Matches things like `1s`, `1.2ms` and `10.2μs` static REGEX_TIMING: Lazy = - Lazy::new(|| Regex::new(r#"[0-9]+(\.[0-9]+)?.s"#).expect("timing regex")); + Lazy::new(|| Regex::new(r"[0-9]+(\.[0-9]+)?.s").expect("timing regex")); /// Matches things like `FilterExec: .*` and `ParquetExec: .*` /// diff --git a/datafusion_util/src/lib.rs b/datafusion_util/src/lib.rs index a043f7f..cd10c04 100755 --- a/datafusion_util/src/lib.rs +++ b/datafusion_util/src/lib.rs @@ -316,7 +316,7 @@ pub fn batch_filter( .evaluate(batch) .map(|v| v.into_array(batch.num_rows())) .and_then(|array| { - array + array? .as_any() .downcast_ref::() .ok_or_else(|| { @@ -397,7 +397,7 @@ mod tests { let ts_predicate_expr = make_range_expr(101, 202, "time"); let expected_string = "TimestampNanosecond(101, None) <= time AND time < TimestampNanosecond(202, None)"; - let actual_string = format!("{ts_predicate_expr:?}"); + let actual_string = ts_predicate_expr.to_string(); assert_eq!(actual_string, expected_string); } diff --git a/influxdb_influxql_parser/src/string.rs b/influxdb_influxql_parser/src/string.rs index 7b586ec..a8a065d 100644 --- a/influxdb_influxql_parser/src/string.rs +++ b/influxdb_influxql_parser/src/string.rs @@ -66,7 +66,7 @@ pub(crate) fn single_quoted_string(i: &str) -> ParseResult<&str, String> { let escaped = preceded( char('\\'), expect( - r#"invalid escape sequence, expected \\, \' or \n"#, + r"invalid escape sequence, expected \\, \' or \n", alt((char('\\'), char('\''), value('\n', char('n')))), ), ); @@ -277,10 +277,10 @@ mod test { ); // escaped characters - let (_, got) = single_quoted_string(r#"'\n\''"#).unwrap(); + let (_, got) = single_quoted_string(r"'\n\''").unwrap(); assert_eq!(got, "\n'"); - let (_, got) = single_quoted_string(r#"'\'hello\''"#).unwrap(); + let (_, got) = single_quoted_string(r"'\'hello\''").unwrap(); assert_eq!(got, "'hello'"); // literal tab @@ -307,8 +307,8 @@ mod test { // Invalid escape assert_expect_error!( - single_quoted_string(r#"'quick\idraw'"#), - r#"invalid escape sequence, expected \\, \' or \n"# + single_quoted_string(r"'quick\idraw'"), + r"invalid escape sequence, expected \\, \' or \n" ); } @@ -318,15 +318,15 @@ mod test { assert_eq!(got, "hello".into()); // handle escaped delimiters "\/" - let (_, got) = regex(r#"/\/this\/is\/a\/path/"#).unwrap(); + let (_, got) = regex(r"/\/this\/is\/a\/path/").unwrap(); assert_eq!(got, "/this/is/a/path".into()); // ignores any other possible escape sequence - let (_, got) = regex(r#"/hello\n/"#).unwrap(); + let (_, got) = regex(r"/hello\n/").unwrap(); assert_eq!(got, "hello\\n".into()); // can parse possible escape sequence at beginning of regex - let (_, got) = regex(r#"/\w.*/"#).unwrap(); + let (_, got) = regex(r"/\w.*/").unwrap(); assert_eq!(got, "\\w.*".into()); // Empty regex @@ -344,6 +344,6 @@ mod test { // Single backslash fails, which matches Go implementation // See: https://go.dev/play/p/_8J1v5-382G - assert_expect_error!(regex(r#"/\/"#), "unterminated regex literal"); + assert_expect_error!(regex(r"/\/"), "unterminated regex literal"); } } diff --git a/iox_query/src/exec/gapfill/algo.rs b/iox_query/src/exec/gapfill/algo.rs index 9040f83..896b7e3 100644 --- a/iox_query/src/exec/gapfill/algo.rs +++ b/iox_query/src/exec/gapfill/algo.rs @@ -6,8 +6,8 @@ mod interpolate; use std::{ops::Range, sync::Arc}; use arrow::{ - array::{Array, ArrayRef, TimestampNanosecondArray, UInt64Array}, - compute::{kernels::take, SortColumn}, + array::{Array, ArrayRef, PrimitiveArray, TimestampNanosecondArray, UInt64Array}, + compute::kernels::take, datatypes::SchemaRef, record_batch::RecordBatch, }; @@ -151,13 +151,11 @@ impl GapFiller { let sort_columns = group_arr .iter() - .map(|(_, arr)| SortColumn { - values: Arc::clone(arr), - options: None, - }) + .map(|(_, arr)| Arc::clone(arr)) .collect::>(); - let mut ranges = arrow::compute::lexicographical_partition_ranges(&sort_columns) - .map_err(DataFusionError::ArrowError)?; + let mut ranges = arrow::compute::partition(&sort_columns)? + .ranges() + .into_iter(); let mut series_ends = vec![]; let mut cursor = self.cursor.clone_for_aggr_col(None)?; @@ -941,7 +939,7 @@ impl StashedAggrBuilder<'_> { /// `input_aggr_array` at `offset` for use with the [`interleave`](arrow::compute::interleave) /// kernel. fn create_stash(input_aggr_array: &ArrayRef, offset: u64) -> Result { - let take_arr = vec![None, Some(offset)].into(); + let take_arr: PrimitiveArray<_> = vec![None, Some(offset)].into(); let stash = take::take(input_aggr_array, &take_arr, None).map_err(DataFusionError::ArrowError)?; Ok(stash) @@ -1170,7 +1168,7 @@ mod tests { let arr = cursor .build_aggr_fill_null(¶ms, &[series], &input_times, &input_aggr_array) .unwrap(); - insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r###" + insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r#" --- - +--------------------------------+------+ - "| time | a0 |" @@ -1183,7 +1181,7 @@ mod tests { - "| 1970-01-01T00:00:00.000001200Z | 12.0 |" - "| 1970-01-01T00:00:00.000001250Z | |" - +--------------------------------+------+ - "###); + "#); assert_cursor_end_state(&cursor, &input_times, ¶ms); } @@ -1215,7 +1213,7 @@ mod tests { .into(); let arr = cursor.build_aggr_fill_null(¶ms, &[series], &input_times, &input_aggr_array)?; - insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r###" + insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r#" --- - +--------------------------------+------+ - "| time | a0 |" @@ -1230,7 +1228,7 @@ mod tests { - "| 1970-01-01T00:00:00.000001200Z | 12.0 |" - "| 1970-01-01T00:00:00.000001250Z | |" - +--------------------------------+------+ - "###); + "#); assert_cursor_end_state(&cursor, &input_times, ¶ms); @@ -1269,7 +1267,7 @@ mod tests { let arr = cursor .build_aggr_fill_prev(¶ms, &[series], &input_times, &input_aggr_array) .unwrap(); - insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r###" + insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r#" --- - +--------------------------------+------+ - "| time | a0 |" @@ -1282,7 +1280,7 @@ mod tests { - "| 1970-01-01T00:00:00.000001200Z | 12.0 |" - "| 1970-01-01T00:00:00.000001250Z | 12.0 |" - +--------------------------------+------+ - "###); + "#); assert_cursor_end_state(&cursor, &input_times, ¶ms); } @@ -1325,7 +1323,7 @@ mod tests { let arr = cursor .build_aggr_fill_prev(¶ms, &[series], &input_times, &input_aggr_array) .unwrap(); - insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r###" + insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r#" --- - +--------------------------------+------+ - "| time | a0 |" @@ -1340,7 +1338,7 @@ mod tests { - "| 1970-01-01T00:00:00.000001200Z | 12.0 |" - "| 1970-01-01T00:00:00.000001250Z | 12.0 |" - +--------------------------------+------+ - "###); + "#); assert_cursor_end_state(&cursor, &input_times, ¶ms); } @@ -1381,7 +1379,7 @@ mod tests { let arr = cursor .build_aggr_fill_null(¶ms, &series_ends, &input_times, &input_aggr_array) .unwrap(); - insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r###" + insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r#" --- - +--------------------------------+------+ - "| time | a0 |" @@ -1395,7 +1393,7 @@ mod tests { - "| 1970-01-01T00:00:00.000001050Z | 11.0 |" - "| 1970-01-01T00:00:00.000001100Z | |" - +--------------------------------+------+ - "###); + "#); assert_cursor_end_state(&cursor, &input_times, ¶ms); } @@ -1445,7 +1443,7 @@ mod tests { let arr = cursor .build_aggr_fill_prev(¶ms, &series_ends, &input_times, &input_aggr_array) .unwrap(); - insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r###" + insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r#" --- - +--------------------------------+------+ - "| time | a0 |" @@ -1459,7 +1457,7 @@ mod tests { - "| 1970-01-01T00:00:00.000001050Z | 21.0 |" - "| 1970-01-01T00:00:00.000001100Z | 21.0 |" - +--------------------------------+------+ - "###); + "#); assert_cursor_end_state(&cursor, &input_times, ¶ms); } @@ -1534,7 +1532,7 @@ mod tests { let arr = cursor .build_aggr_fill_prev_stashed(¶ms, &series_ends, &input_times, &input_aggr_array) .unwrap(); - insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r###" + insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r#" --- - +--------------------------------+-------+ - "| time | a0 |" @@ -1550,7 +1548,7 @@ mod tests { - "| 1970-01-01T00:00:00.000001100Z | 21.1 |" - "| 1970-01-01T00:00:00.000001150Z | 21.1 |" - +--------------------------------+-------+ - "###); + "#); assert_cursor_end_state(&cursor, &input_times, ¶ms); } diff --git a/iox_query/src/exec/gapfill/algo/interpolate.rs b/iox_query/src/exec/gapfill/algo/interpolate.rs index 7995501..fe56705 100644 --- a/iox_query/src/exec/gapfill/algo/interpolate.rs +++ b/iox_query/src/exec/gapfill/algo/interpolate.rs @@ -365,7 +365,7 @@ mod test { let arr = cursor .build_aggr_fill_interpolate(¶ms, &series_ends, &input_times, &input_aggr_array) .unwrap(); - insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r###" + insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r#" --- - +--------------------------------+------+ - "| time | a0 |" @@ -382,7 +382,7 @@ mod test { - "| 1970-01-01T00:00:00.000001900Z | 0 |" - "| 1970-01-01T00:00:00.000002Z | |" - +--------------------------------+------+ - "###); + "#); assert_cursor_end_state(&cursor, &input_times, ¶ms); } @@ -437,7 +437,7 @@ mod test { let arr = cursor .build_aggr_fill_interpolate(¶ms, &series_ends, &input_times, &input_aggr_array) .unwrap(); - insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r###" + insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r#" --- - +--------------------------------+------+ - "| time | a0 |" @@ -454,7 +454,7 @@ mod test { - "| 1970-01-01T00:00:00.000001900Z | 0 |" - "| 1970-01-01T00:00:00.000002Z | |" - +--------------------------------+------+ - "###); + "#); assert_cursor_end_state(&cursor, &input_times, ¶ms); } @@ -509,7 +509,7 @@ mod test { let arr = cursor .build_aggr_fill_interpolate(¶ms, &series_ends, &input_times, &input_aggr_array) .unwrap(); - insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r###" + insta::assert_yaml_snapshot!(array_to_lines(&time_arr, &arr), @r#" --- - +--------------------------------+--------+ - "| time | a0 |" @@ -526,7 +526,7 @@ mod test { - "| 1970-01-01T00:00:00.000001900Z | 0.0 |" - "| 1970-01-01T00:00:00.000002Z | |" - +--------------------------------+--------+ - "###); + "#); assert_cursor_end_state(&cursor, &input_times, ¶ms); } diff --git a/iox_query/src/exec/gapfill/exec_tests.rs b/iox_query/src/exec/gapfill/exec_tests.rs index e2f8789..899765f 100644 --- a/iox_query/src/exec/gapfill/exec_tests.rs +++ b/iox_query/src/exec/gapfill/exec_tests.rs @@ -48,7 +48,7 @@ fn test_gapfill_simple() { // TestCase when running with a memory limit. let batches = tc.run_with_memory_limit(16384).unwrap(); let actual = batches_to_lines(&batches); - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+--------------------------+----+ - "| g0 | time | a0 |" @@ -61,7 +61,7 @@ fn test_gapfill_simple() { - "| a | 1970-01-01T00:00:01.100Z | 11 |" - "| a | 1970-01-01T00:00:01.125Z | |" - +----+--------------------------+----+ - "###); + "#); assert_batch_count(&batches, output_batch_size); } }} @@ -89,7 +89,7 @@ fn test_gapfill_simple_no_group_no_aggr() { }; let batches = tc.run().unwrap(); let actual = batches_to_lines(&batches); - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +--------------------------+ - "| time |" @@ -103,7 +103,7 @@ fn test_gapfill_simple_no_group_no_aggr() { - "| 1970-01-01T00:00:01.100Z |" - "| 1970-01-01T00:00:01.125Z |" - +--------------------------+ - "###); + "#); assert_batch_count(&batches, output_batch_size); } }} @@ -128,7 +128,7 @@ fn test_gapfill_multi_group_simple() { }; let batches = tc.run().unwrap(); let actual = batches_to_lines(&batches); - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+--------------------------+----+ - "| g0 | time | a0 |" @@ -148,7 +148,7 @@ fn test_gapfill_multi_group_simple() { - "| b | 1970-01-01T00:00:01.100Z | |" - "| b | 1970-01-01T00:00:01.125Z | |" - +----+--------------------------+----+ - "###); + "#); assert_batch_count(&batches, output_batch_size); } }} @@ -197,7 +197,7 @@ fn test_gapfill_multi_group_with_nulls() { }; let batches = tc.run().unwrap(); let actual = batches_to_lines(&batches); - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+--------------------------+----+ - "| g0 | time | a0 |" @@ -220,7 +220,7 @@ fn test_gapfill_multi_group_with_nulls() { - "| b | 1970-01-01T00:00:01.100Z | 21 |" - "| b | 1970-01-01T00:00:01.125Z | |" - +----+--------------------------+----+ - "###); + "#); assert_batch_count(&batches, output_batch_size); } }} @@ -280,7 +280,7 @@ fn test_gapfill_multi_group_cols_with_nulls() { }; let batches = tc.run().unwrap(); let actual = batches_to_lines(&batches); - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+----+--------------------------+----+ - "| g0 | g1 | time | a0 |" @@ -303,7 +303,7 @@ fn test_gapfill_multi_group_cols_with_nulls() { - "| a | d | 1970-01-01T00:00:01.100Z | 21 |" - "| a | d | 1970-01-01T00:00:01.125Z | |" - +----+----+--------------------------+----+ - "###); + "#); assert_batch_count(&batches, output_batch_size); } }} @@ -340,7 +340,7 @@ fn test_gapfill_multi_group_cols_with_more_nulls() { }; let batches = tc.run().unwrap(); let actual = batches_to_lines(&batches); - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+--------------------------+----+ - "| g0 | time | a0 |" @@ -356,7 +356,7 @@ fn test_gapfill_multi_group_cols_with_more_nulls() { - "| b | 1970-01-01T00:00:01Z | |" - "| b | 1970-01-01T00:00:01.025Z | |" - +----+--------------------------+----+ - "###); + "#); assert_batch_count(&batches, output_batch_size); } }} @@ -427,7 +427,7 @@ fn test_gapfill_multi_aggr_cols_with_nulls() { }; let batches = tc.run().unwrap(); let actual = batches_to_lines(&batches); - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+----+--------------------------+----+----+ - "| g0 | g1 | time | a0 | a1 |" @@ -450,7 +450,7 @@ fn test_gapfill_multi_aggr_cols_with_nulls() { - "| b | d | 1970-01-01T00:00:01.100Z | 21 | 41 |" - "| b | d | 1970-01-01T00:00:01.125Z | | |" - +----+----+--------------------------+----+----+ - "###); + "#); assert_batch_count(&batches, output_batch_size); } }} @@ -475,7 +475,7 @@ fn test_gapfill_simple_no_lower_bound() { }; let batches = tc.run().unwrap(); let actual = batches_to_lines(&batches); - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+--------------------------+----+ - "| g0 | time | a0 |" @@ -490,7 +490,7 @@ fn test_gapfill_simple_no_lower_bound() { - "| b | 1970-01-01T00:00:01.100Z | 21 |" - "| b | 1970-01-01T00:00:01.125Z | |" - +----+--------------------------+----+ - "###); + "#); assert_batch_count(&batches, output_batch_size); } }} @@ -546,7 +546,7 @@ fn test_gapfill_fill_prev() { insta::with_settings!({ description => format!("input_batch_size: {input_batch_size}, output_batch_size: {output_batch_size}"), }, { - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+--------------------------+----+ - "| g0 | time | a0 |" @@ -566,7 +566,7 @@ fn test_gapfill_fill_prev() { - "| b | 1970-01-01T00:00:01.100Z | 21 |" - "| b | 1970-01-01T00:00:01.125Z | 21 |" - +----+--------------------------+----+ - "###) + "#) }); assert_batch_count(&batches, output_batch_size); } @@ -624,7 +624,7 @@ fn test_gapfill_fill_prev_null_as_missing() { insta::with_settings!({ description => format!("input_batch_size: {input_batch_size}, output_batch_size: {output_batch_size}"), }, { - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+--------------------------+----+ - "| g0 | time | a0 |" @@ -644,7 +644,7 @@ fn test_gapfill_fill_prev_null_as_missing() { - "| b | 1970-01-01T00:00:01.100Z | 21 |" - "| b | 1970-01-01T00:00:01.125Z | 21 |" - +----+--------------------------+----+ - "###) + "#) }); assert_batch_count(&batches, output_batch_size); } @@ -723,7 +723,7 @@ fn test_gapfill_fill_prev_null_as_missing_many_nulls() { insta::with_settings!({ description => format!("input_batch_size: {input_batch_size}, output_batch_size: {output_batch_size}"), }, { - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+--------------------------+----+ - "| g0 | time | a0 |" @@ -745,7 +745,7 @@ fn test_gapfill_fill_prev_null_as_missing_many_nulls() { - "| b | 1970-01-01T00:00:01.100Z | 22 |" - "| b | 1970-01-01T00:00:01.125Z | 22 |" - +----+--------------------------+----+ - "###) + "#) }); assert_batch_count(&batches, output_batch_size); } @@ -833,7 +833,7 @@ fn test_gapfill_fill_interpolate() { insta::with_settings!({ description => format!("input_batch_size: {input_batch_size}, output_batch_size: {output_batch_size}"), }, { - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+--------------------------+------+ - "| g0 | time | a0 |" @@ -855,7 +855,7 @@ fn test_gapfill_fill_interpolate() { - "| b | 1970-01-01T00:00:01.100Z | 1450 |" - "| b | 1970-01-01T00:00:01.125Z | 1550 |" - +----+--------------------------+------+ - "###) + "#) }); assert_batch_count(&batches, output_batch_size); } @@ -920,7 +920,7 @@ fn test_gapfill_simple_no_lower_bound_with_nulls() { }; let batches = tc.run().unwrap(); let actual = batches_to_lines(&batches); - insta::assert_yaml_snapshot!(actual, @r###" + insta::assert_yaml_snapshot!(actual, @r#" --- - +----+--------------------------+----+ - "| g0 | time | a0 |" @@ -943,7 +943,7 @@ fn test_gapfill_simple_no_lower_bound_with_nulls() { - "| c | 1970-01-01T00:00:01.100Z | 21 |" - "| c | 1970-01-01T00:00:01.125Z | |" - +----+--------------------------+----+ - "###); + "#); assert_batch_count(&batches, output_batch_size); } }} @@ -1083,7 +1083,7 @@ struct TestCase { impl TestCase { fn run(self) -> Result> { block_on(async { - let session_ctx = SessionContext::with_config( + let session_ctx = SessionContext::new_with_config( SessionConfig::default().with_batch_size(self.output_batch_size), ) .into(); @@ -1093,7 +1093,7 @@ impl TestCase { fn run_with_memory_limit(self, limit: usize) -> Result> { block_on(async { - let session_ctx = SessionContext::with_config_rt( + let session_ctx = SessionContext::new_with_config_rt( SessionConfig::default().with_batch_size(self.output_batch_size), RuntimeEnv::new(RuntimeConfig::default().with_memory_limit(limit, 1.0))?.into(), ) diff --git a/iox_query/src/exec/gapfill/mod.rs b/iox_query/src/exec/gapfill/mod.rs index 4833967..1bfe035 100644 --- a/iox_query/src/exec/gapfill/mod.rs +++ b/iox_query/src/exec/gapfill/mod.rs @@ -528,8 +528,8 @@ impl ExecutionPlan for GapFillExec { )?)) } - fn statistics(&self) -> Statistics { - Statistics::default() + fn statistics(&self) -> std::result::Result { + Ok(Statistics::new_unknown(&self.schema())) } } diff --git a/iox_query/src/exec/gapfill/stream.rs b/iox_query/src/exec/gapfill/stream.rs index accaa37..5d078eb 100644 --- a/iox_query/src/exec/gapfill/stream.rs +++ b/iox_query/src/exec/gapfill/stream.rs @@ -218,7 +218,7 @@ impl GapFillStream { let input_time_array = self .time_expr .evaluate(&input_batch)? - .into_array(input_batch.num_rows()); + .into_array(input_batch.num_rows())?; let input_time_array: &TimestampNanosecondArray = input_time_array .as_any() .downcast_ref() @@ -261,7 +261,8 @@ impl GapFillStream { .map(|e| { Ok(( expr_to_index(e), - e.evaluate(input_batch)?.into_array(input_batch.num_rows()), + e.evaluate(input_batch)? + .into_array(input_batch.num_rows())?, )) }) .collect::>>() @@ -275,7 +276,8 @@ impl GapFillStream { .map(|e| { Ok(( expr_to_index(e), - e.evaluate(input_batch)?.into_array(input_batch.num_rows()), + e.evaluate(input_batch)? + .into_array(input_batch.num_rows())?, )) }) .collect::>>() diff --git a/iox_query/src/exec/non_null_checker.rs b/iox_query/src/exec/non_null_checker.rs index 1de84cc..3cfd5da 100644 --- a/iox_query/src/exec/non_null_checker.rs +++ b/iox_query/src/exec/non_null_checker.rs @@ -276,9 +276,9 @@ impl ExecutionPlan for NonNullCheckerExec { Some(self.metrics.clone_inner()) } - fn statistics(&self) -> Statistics { + fn statistics(&self) -> std::result::Result { // don't know anything about the statistics - Statistics::default() + Ok(Statistics::new_unknown(&self.schema())) } } diff --git a/iox_query/src/exec/schema_pivot.rs b/iox_query/src/exec/schema_pivot.rs index b6192f6..88f334c 100644 --- a/iox_query/src/exec/schema_pivot.rs +++ b/iox_query/src/exec/schema_pivot.rs @@ -251,9 +251,9 @@ impl ExecutionPlan for SchemaPivotExec { Some(self.metrics.clone_inner()) } - fn statistics(&self) -> Statistics { + fn statistics(&self) -> std::result::Result { // don't know anything about the statistics - Statistics::default() + Ok(Statistics::new_unknown(&self.schema())) } } diff --git a/iox_query/src/exec/split.rs b/iox_query/src/exec/split.rs index d30a4bc..c1b16ac 100644 --- a/iox_query/src/exec/split.rs +++ b/iox_query/src/exec/split.rs @@ -274,10 +274,10 @@ impl ExecutionPlan for StreamSplitExec { Some(self.metrics.clone_inner()) } - fn statistics(&self) -> Statistics { + fn statistics(&self) -> std::result::Result { // For now, don't return any statistics (in the future we // could potentially estimate the output cardinalities) - Statistics::default() + Ok(Statistics::new_unknown(&self.schema())) } } @@ -490,7 +490,7 @@ fn negate(v: &ColumnarValue) -> Result { } else { let msg = format!( "Expected boolean literal, but got type {:?}", - val.get_datatype() + val.data_type() ); Err(DataFusionError::Internal(msg)) } @@ -515,8 +515,8 @@ fn and(left: &ColumnarValue, right: &ColumnarValue) -> Result { } else { let msg = format!( "Expected two boolean literals, but got type {:?} and type {:?}", - val_left.get_datatype(), - val_right.get_datatype() + val_left.data_type(), + val_right.data_type() ); Err(DataFusionError::Internal(msg)) } diff --git a/iox_query/src/logical_optimizer/handle_gapfill.rs b/iox_query/src/logical_optimizer/handle_gapfill.rs index 999e536..1445607 100644 --- a/iox_query/src/logical_optimizer/handle_gapfill.rs +++ b/iox_query/src/logical_optimizer/handle_gapfill.rs @@ -8,9 +8,8 @@ use datafusion::{ common::tree_node::{RewriteRecursion, TreeNode, TreeNodeRewriter, VisitRecursion}, error::{DataFusionError, Result}, logical_expr::{ - expr::{ScalarFunction, ScalarUDF}, - utils::expr_to_columns, - Aggregate, BuiltinScalarFunction, Extension, LogicalPlan, Projection, + expr::ScalarFunction, utils::expr_to_columns, Aggregate, BuiltinScalarFunction, Extension, + LogicalPlan, Projection, }, optimizer::{optimizer::ApplyOrder, OptimizerConfig, OptimizerRule}, prelude::{col, Expr}, @@ -193,7 +192,12 @@ fn build_gapfill_node( let time_column = col(new_aggr_plan.schema().fields()[date_bin_gapfill_index].qualified_column()); - let aggr = Aggregate::try_from_plan(&new_aggr_plan)?; + let aggr = match &new_aggr_plan { + LogicalPlan::Aggregate(it) => Ok(it), + _ => Err(DataFusionError::Plan( + "Could not coerce into Aggregate!".to_string(), + )), + }?; let mut new_group_expr: Vec<_> = aggr .schema .fields() @@ -329,7 +333,9 @@ impl TreeNodeRewriter for DateBinGapfillRewriter { type N = Expr; fn pre_visit(&mut self, expr: &Expr) -> Result { match expr { - Expr::ScalarUDF(ScalarUDF { fun, .. }) if fun.name == DATE_BIN_GAPFILL_UDF_NAME => { + Expr::ScalarFunction(ScalarFunction { func_def, .. }) + if func_def.name() == DATE_BIN_GAPFILL_UDF_NAME => + { Ok(RewriteRecursion::Mutate) } _ => Ok(RewriteRecursion::Continue), @@ -338,12 +344,14 @@ impl TreeNodeRewriter for DateBinGapfillRewriter { fn mutate(&mut self, expr: Expr) -> Result { match expr { - Expr::ScalarUDF(ScalarUDF { fun, args }) if fun.name == DATE_BIN_GAPFILL_UDF_NAME => { + Expr::ScalarFunction(ScalarFunction { func_def, args }) + if func_def.name() == DATE_BIN_GAPFILL_UDF_NAME => + { self.args = Some(args.clone()); - Ok(Expr::ScalarFunction(ScalarFunction { - fun: BuiltinScalarFunction::DateBin, + Ok(Expr::ScalarFunction(ScalarFunction::new( + BuiltinScalarFunction::DateBin, args, - })) + ))) } _ => Ok(expr), } @@ -363,16 +371,19 @@ fn handle_projection(proj: &Projection) -> Result> { }) else { // If this is not a projection that is a parent to a GapFill node, // then there is nothing to do. - return Ok(None) + return Ok(None); }; let fill_cols: Vec<(&Expr, FillStrategy)> = proj_exprs .iter() .filter_map(|e| match e { - Expr::ScalarUDF(ScalarUDF { fun, args }) if fun.name == LOCF_UDF_NAME => { + Expr::ScalarFunction(ScalarFunction { func_def, args }) + if func_def.name() == LOCF_UDF_NAME => + { let col = &args[0]; Some((col, FillStrategy::PrevNullAsMissing)) } + _ => None, }) .collect(); @@ -398,7 +409,9 @@ fn handle_projection(proj: &Projection) -> Result> { .iter() .cloned() .map(|e| match e { - Expr::ScalarUDF(ScalarUDF { fun, mut args }) if fun.name == LOCF_UDF_NAME => { + Expr::ScalarFunction(ScalarFunction { func_def, mut args }) + if func_def.name() == LOCF_UDF_NAME => + { args.remove(0) } _ => e, @@ -422,7 +435,7 @@ fn count_udf(e: &Expr, name: &str) -> Result { let mut count = 0; e.apply(&mut |expr| { match expr { - Expr::ScalarUDF(ScalarUDF { fun, .. }) if fun.name == name => { + Expr::ScalarFunction(func_def, ..) if func_def.func_def.name() == name => { count += 1; } _ => (), @@ -457,7 +470,7 @@ mod test { use arrow::datatypes::{DataType, Field, Schema, TimeUnit}; use datafusion::error::Result; - use datafusion::logical_expr::expr::ScalarUDF; + use datafusion::logical_expr::expr::ScalarFunction; use datafusion::logical_expr::{logical_plan, LogicalPlan, LogicalPlanBuilder}; use datafusion::optimizer::optimizer::Optimizer; use datafusion::optimizer::OptimizerContext; @@ -488,21 +501,21 @@ mod test { } fn date_bin_gapfill_with_origin(interval: Expr, time: Expr, origin: Expr) -> Result { - Ok(Expr::ScalarUDF(ScalarUDF { - fun: query_functions::registry().udf(DATE_BIN_GAPFILL_UDF_NAME)?, - args: vec![interval, time, origin], - })) + Ok(Expr::ScalarFunction(ScalarFunction::new_udf( + query_functions::registry().udf(DATE_BIN_GAPFILL_UDF_NAME)?, + vec![interval, time, origin], + ))) } fn locf(arg: Expr) -> Result { - Ok(Expr::ScalarUDF(ScalarUDF { - fun: query_functions::registry().udf(LOCF_UDF_NAME)?, - args: vec![arg], - })) + Ok(Expr::ScalarFunction(ScalarFunction::new_udf( + query_functions::registry().udf(LOCF_UDF_NAME)?, + vec![arg], + ))) } fn optimize(plan: &LogicalPlan) -> Result> { - let optimizer = Optimizer::with_rules(vec![Arc::new(HandleGapFill::default())]); + let optimizer = Optimizer::with_rules(vec![Arc::new(HandleGapFill)]); optimizer.optimize_recursively( optimizer.rules.get(0).unwrap(), plan, diff --git a/iox_query/src/logical_optimizer/handle_gapfill/range_predicate.rs b/iox_query/src/logical_optimizer/handle_gapfill/range_predicate.rs index b5ed5af..1a2cbcc 100644 --- a/iox_query/src/logical_optimizer/handle_gapfill/range_predicate.rs +++ b/iox_query/src/logical_optimizer/handle_gapfill/range_predicate.rs @@ -7,7 +7,7 @@ use datafusion::{ DFSchema, }, error::Result, - logical_expr::{expr::Alias, Between, BinaryExpr, LogicalPlan, Operator}, + logical_expr::{Between, BinaryExpr, LogicalPlan, Operator}, optimizer::utils::split_conjunction, prelude::{Column, Expr}, }; @@ -70,15 +70,6 @@ impl TreeNodeVisitor for TimeRangeVisitor { } } -fn unwrap_alias(mut e: &Expr) -> &Expr { - loop { - match e { - Expr::Alias(Alias { expr, .. }) => e = expr.as_ref(), - e => break e, - } - } -} - /// Encapsulates the upper and lower bounds of a time column /// in a logical plan. #[derive(Clone)] diff --git a/iox_query/src/logical_optimizer/influx_regex_to_datafusion_regex.rs b/iox_query/src/logical_optimizer/influx_regex_to_datafusion_regex.rs index 799e382..2542bd3 100644 --- a/iox_query/src/logical_optimizer/influx_regex_to_datafusion_regex.rs +++ b/iox_query/src/logical_optimizer/influx_regex_to_datafusion_regex.rs @@ -2,8 +2,7 @@ use datafusion::{ common::{tree_node::TreeNodeRewriter, DFSchema}, error::DataFusionError, logical_expr::{ - expr::ScalarUDF, expr_rewriter::rewrite_preserving_name, utils::from_plan, LogicalPlan, - Operator, + expr::ScalarFunction, expr_rewriter::rewrite_preserving_name, LogicalPlan, Operator, }, optimizer::{OptimizerConfig, OptimizerRule}, prelude::{binary_expr, lit, Expr}, @@ -67,7 +66,7 @@ fn optimize(plan: &LogicalPlan) -> Result { .map(|expr| rewrite_preserving_name(expr, &mut expr_rewriter)) .collect::, DataFusionError>>()?; - from_plan(plan, new_exprs.as_slice(), new_inputs.as_slice()) + plan.with_new_exprs(new_exprs, &new_inputs) } impl TreeNodeRewriter for InfluxRegexToDataFusionRegex { @@ -75,14 +74,14 @@ impl TreeNodeRewriter for InfluxRegexToDataFusionRegex { fn mutate(&mut self, expr: Expr) -> Result { match expr { - Expr::ScalarUDF(ScalarUDF { fun, mut args }) => { + Expr::ScalarFunction(ScalarFunction { func_def, mut args }) => { if (args.len() == 2) - && ((fun.name == REGEX_MATCH_UDF_NAME) - || (fun.name == REGEX_NOT_MATCH_UDF_NAME)) + && ((func_def.name() == REGEX_MATCH_UDF_NAME) + || (func_def.name() == REGEX_NOT_MATCH_UDF_NAME)) { if let Expr::Literal(ScalarValue::Utf8(Some(s))) = &args[1] { let s = clean_non_meta_escapes(s); - let op = match fun.name.as_str() { + let op = match func_def.name() { REGEX_MATCH_UDF_NAME => Operator::RegexMatch, REGEX_NOT_MATCH_UDF_NAME => Operator::RegexNotMatch, _ => unreachable!(), @@ -90,8 +89,7 @@ impl TreeNodeRewriter for InfluxRegexToDataFusionRegex { return Ok(binary_expr(args.remove(0), op, lit(s))); } } - - Ok(Expr::ScalarUDF(ScalarUDF { fun, args })) + Ok(Expr::ScalarFunction(ScalarFunction { func_def, args })) } _ => Ok(expr), } diff --git a/iox_query_influxql/src/frontend/planner.rs b/iox_query_influxql/src/frontend/planner.rs index 069bfd3..9539900 100644 --- a/iox_query_influxql/src/frontend/planner.rs +++ b/iox_query_influxql/src/frontend/planner.rs @@ -111,7 +111,7 @@ impl ExecutionPlan for SchemaExec { self.input.execute(partition, context) } - fn statistics(&self) -> Statistics { + fn statistics(&self) -> Result { self.input.statistics() } } diff --git a/iox_query_influxql/src/plan/planner.rs b/iox_query_influxql/src/plan/planner.rs index 94b915b..b7fbdf5 100644 --- a/iox_query_influxql/src/plan/planner.rs +++ b/iox_query_influxql/src/plan/planner.rs @@ -21,12 +21,13 @@ use datafusion::logical_expr::expr_rewriter::normalize_col; use datafusion::logical_expr::logical_plan::builder::project; use datafusion::logical_expr::logical_plan::Analyze; use datafusion::logical_expr::utils::{expr_as_column_expr, find_aggregate_exprs}; +use datafusion::logical_expr::{self, ScalarFunctionDefinition}; use datafusion::logical_expr::{ binary_expr, col, date_bin, expr, expr::WindowFunction, lit, lit_timestamp_nano, now, - window_function, Aggregate, AggregateFunction, AggregateUDF, Between, BinaryExpr, - BuiltInWindowFunction, BuiltinScalarFunction, EmptyRelation, Explain, Expr, ExprSchemable, - Extension, LogicalPlan, LogicalPlanBuilder, Operator, PlanType, ScalarUDF, TableSource, - ToStringifiedPlan, WindowFrame, WindowFrameBound, WindowFrameUnits, + window_function, AggregateFunction, AggregateUDF, Between, BinaryExpr, BuiltInWindowFunction, + BuiltinScalarFunction, EmptyRelation, Explain, Expr, ExprSchemable, Extension, LogicalPlan, + LogicalPlanBuilder, Operator, PlanType, ScalarUDF, TableSource, ToStringifiedPlan, WindowFrame, + WindowFrameBound, WindowFrameUnits, }; use datafusion_util::{lit_dict, AsExpr}; use generated_types::influxdata::iox::querier::v1::InfluxQlMetadata; @@ -444,7 +445,7 @@ impl<'a> InfluxQLToLogicalPlan<'a> { // projection expressions includes the `iox::measurement` column let proj_exprs = proj .into_iter() - .chain(select_exprs_post_aggr.into_iter()) + .chain(select_exprs_post_aggr) .collect::>(); // Wrap the plan in a `LogicalPlan::Projection` from the select expressions @@ -561,7 +562,9 @@ impl<'a> InfluxQLToLogicalPlan<'a> { } let Some(time_column_index) = find_time_column_index(fields) else { - return Err(DataFusionError::Internal("unable to find time column".to_owned())) + return Err(DataFusionError::Internal( + "unable to find time column".to_owned(), + )); }; // Find a list of unique aggregate expressions from the projection. @@ -635,7 +638,11 @@ impl<'a> InfluxQLToLogicalPlan<'a> { { let args = match select_exprs[time_column_index].clone().unalias() { Expr::ScalarFunction(ScalarFunction { - fun: BuiltinScalarFunction::DateBin, + func_def: + ScalarFunctionDefinition::BuiltIn { + fun: BuiltinScalarFunction::DateBin, + .. + }, args, }) => args, _ => { @@ -1081,13 +1088,13 @@ impl<'a> InfluxQLToLogicalPlan<'a> { "invalid number of arguments for log, expected 2, got 1".to_owned(), )) } else { - Ok(Expr::ScalarFunction(ScalarFunction { - fun: BuiltinScalarFunction::Log, - args: args.into_iter().rev().collect(), - })) + Ok(Expr::ScalarFunction(ScalarFunction::new( + BuiltinScalarFunction::Log, + args.into_iter().rev().collect(), + ))) } } - fun => Ok(Expr::ScalarFunction(ScalarFunction { fun, args })), + fun => Ok(Expr::ScalarFunction(ScalarFunction::new(fun, args))), } } @@ -1153,7 +1160,10 @@ impl<'a> InfluxQLToLogicalPlan<'a> { MeasurementSelection::Subquery(_) => Err(DataFusionError::NotImplemented( "subquery in FROM clause".into(), )), - }? else { continue }; + }? + else { + continue; + }; table_projs.push_back(table_proj); } Ok(table_projs) @@ -1230,7 +1240,12 @@ fn build_gap_fill_node( ))); }; - let aggr = Aggregate::try_from_plan(&input)?; + let aggr = match &input { + LogicalPlan::Aggregate(ref it) => Ok(it), + _ => Err(DataFusionError::Plan( + "Could not coerce into Aggregate!".to_string(), + )), + }?; let mut new_group_expr: Vec<_> = aggr .schema .fields() @@ -1360,7 +1375,9 @@ fn plan_with_metadata(plan: LogicalPlan, metadata: &InfluxQlMetadata) -> Result< } LogicalPlan::Distinct(src) => { let mut v = src.clone(); - v.input = Arc::new(set_schema(&src.input, metadata)?); + if let logical_expr::Distinct::On(x) = &mut v { + x.input = Arc::new(set_schema(&x.input, metadata)?); + } LogicalPlan::Distinct(v) } LogicalPlan::Unnest(src) => { @@ -1692,11 +1709,11 @@ mod test { #[test] fn test_scalar_functions() { // LOG requires two arguments, and first argument is field - assert_snapshot!(plan("SELECT LOG(usage_idle, 8) FROM cpu"), @r###" + assert_snapshot!(plan("SELECT LOG(usage_idle, 8) FROM cpu"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), log:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, log(Int64(8), cpu.usage_idle) AS log [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), log:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); // Fallible @@ -1786,7 +1803,7 @@ mod test { #[ignore = "incompatible schema with CeresDB"] #[test] fn test_from_zero_to_many() { - assert_snapshot!(plan("SELECT host, cpu, device, usage_idle, bytes_used FROM cpu, disk"), @r###" + assert_snapshot!(plan("SELECT host, cpu, device, usage_idle, bytes_used FROM cpu, disk"), @r#" Sort: iox::measurement ASC NULLS LAST, time ASC NULLS LAST, cpu ASC NULLS LAST, device ASC NULLS LAST, host ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, cpu:Utf8;N, device:Utf8;N, usage_idle:Float64;N, bytes_used:Int64;N] Union [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, cpu:Utf8;N, device:Utf8;N, usage_idle:Float64;N, bytes_used:Int64;N] Projection: iox::measurement, time, host, CAST(cpu AS Utf8) AS cpu, CAST(device AS Utf8) AS device, usage_idle, CAST(bytes_used AS Int64) AS bytes_used [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, cpu:Utf8;N, device:Utf8;N, usage_idle:Float64;N, bytes_used:Int64;N] @@ -1797,18 +1814,18 @@ mod test { Sort: time ASC NULLS LAST, device ASC NULLS LAST, host ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, cpu:Null;N, device:Dictionary(Int32, Utf8);N, usage_idle:Null;N, bytes_used:Int64;N] Projection: Dictionary(Int32, Utf8("disk")) AS iox::measurement, disk.time AS time, disk.host AS host, NULL AS cpu, disk.device AS device, NULL AS usage_idle, disk.bytes_used AS bytes_used [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, cpu:Null;N, device:Dictionary(Int32, Utf8);N, usage_idle:Null;N, bytes_used:Int64;N] TableScan: disk [bytes_free:Int64;N, bytes_used:Int64;N, device:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None)] - "###); + "#); // nonexistent assert_snapshot!(plan("SELECT host, usage_idle FROM non_existent"), @"EmptyRelation []"); - assert_snapshot!(plan("SELECT host, usage_idle FROM cpu, non_existent"), @r###" + assert_snapshot!(plan("SELECT host, usage_idle FROM cpu, non_existent"), @r#" Sort: time ASC NULLS LAST, host ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.host AS host, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); // multiple of same measurement - assert_snapshot!(plan("SELECT host, usage_idle FROM cpu, cpu"), @r###" + assert_snapshot!(plan("SELECT host, usage_idle FROM cpu, cpu"), @r#" Sort: iox::measurement ASC NULLS LAST, time ASC NULLS LAST, host ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Union [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Sort: time ASC NULLS LAST, host ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] @@ -1817,7 +1834,7 @@ mod test { Sort: time ASC NULLS LAST, host ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.host AS host, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), host:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); } // TODO: make schema compatible. @@ -1825,87 +1842,87 @@ mod test { #[test] fn test_time_range_in_where() { assert_snapshot!( - plan("SELECT foo, f64_field FROM data where time > now() - 10s"), @r###" + plan("SELECT foo, f64_field FROM data where time > now() - 10s"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Filter: data.time > now() - IntervalMonthDayNano("10000000000") [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "### + "# ); assert_snapshot!( - plan("SELECT foo, f64_field FROM data where time > '2004-04-09T02:33:45Z'"), @r###" + plan("SELECT foo, f64_field FROM data where time > '2004-04-09T02:33:45Z'"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Filter: data.time > TimestampNanosecond(1081478025000000000, None) [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "### + "# ); assert_snapshot!( - plan("SELECT foo, f64_field FROM data where time > '2004-04-09T'"), @r###"Error during planning: invalid expression "'2004-04-09T'": '2004-04-09T' is not a valid timestamp"### + plan("SELECT foo, f64_field FROM data where time > '2004-04-09T'"), @r#"Error during planning: invalid expression "'2004-04-09T'": '2004-04-09T' is not a valid timestamp"# ); // time on the right-hand side assert_snapshot!( - plan("SELECT foo, f64_field FROM data where now() - 10s < time"), @r###" + plan("SELECT foo, f64_field FROM data where now() - 10s < time"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Filter: now() - IntervalMonthDayNano("10000000000") < data.time [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "### + "# ); // Regular expression equality tests - assert_snapshot!(plan("SELECT foo, f64_field FROM data where foo =~ /f/"), @r###" + assert_snapshot!(plan("SELECT foo, f64_field FROM data where foo =~ /f/"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Filter: CAST(data.foo AS Utf8) ~ Utf8("f") [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // regular expression for a numeric field is rewritten to `false` - assert_snapshot!(plan("SELECT foo, f64_field FROM data where f64_field =~ /f/"), @r###" + assert_snapshot!(plan("SELECT foo, f64_field FROM data where f64_field =~ /f/"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Filter: Boolean(false) [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // regular expression for a non-existent field is rewritten to `false` assert_snapshot!( - plan("SELECT foo, f64_field FROM data where non_existent =~ /f/"), @r###" + plan("SELECT foo, f64_field FROM data where non_existent =~ /f/"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Filter: Boolean(false) [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "### + "# ); // Regular expression inequality tests - assert_snapshot!(plan("SELECT foo, f64_field FROM data where foo !~ /f/"), @r###" + assert_snapshot!(plan("SELECT foo, f64_field FROM data where foo !~ /f/"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Filter: CAST(data.foo AS Utf8) !~ Utf8("f") [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // regular expression for a numeric field is rewritten to `false` - assert_snapshot!(plan("SELECT foo, f64_field FROM data where f64_field !~ /f/"), @r###" + assert_snapshot!(plan("SELECT foo, f64_field FROM data where f64_field !~ /f/"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Filter: Boolean(false) [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // regular expression for a non-existent field is rewritten to `false` assert_snapshot!( - plan("SELECT foo, f64_field FROM data where non_existent !~ /f/"), @r###" + plan("SELECT foo, f64_field FROM data where non_existent !~ /f/"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Filter: Boolean(false) [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "### + "# ); } @@ -1914,74 +1931,74 @@ mod test { #[test] fn test_column_matching_rules() { // Cast between numeric types - assert_snapshot!(plan("SELECT f64_field::integer FROM data"), @r###" + assert_snapshot!(plan("SELECT f64_field::integer FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, CAST(data.f64_field AS Int64) AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT i64_field::float FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT i64_field::float FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, CAST(data.i64_field AS Float64) AS i64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // use field selector - assert_snapshot!(plan("SELECT bool_field::field FROM data"), @r###" + assert_snapshot!(plan("SELECT bool_field::field FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Boolean;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.bool_field AS bool_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Boolean;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // invalid column reference assert_snapshot!(plan("SELECT not_exists::tag FROM data"), @"EmptyRelation []"); assert_snapshot!(plan("SELECT not_exists::field FROM data"), @"EmptyRelation []"); // Returns NULL for invalid casts - assert_snapshot!(plan("SELECT f64_field::string FROM data"), @r###" + assert_snapshot!(plan("SELECT f64_field::string FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Null;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, NULL AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Null;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT f64_field::boolean FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT f64_field::boolean FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Null;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, NULL AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Null;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT str_field::boolean FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT str_field::boolean FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Null;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, NULL AS str_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Null;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); } // TODO: make schema compatible. #[ignore = "incompatible schema with CeresDB"] #[test] fn test_explain() { - assert_snapshot!(plan("EXPLAIN SELECT foo, f64_field FROM data"), @r###" + assert_snapshot!(plan("EXPLAIN SELECT foo, f64_field FROM data"), @r#" Explain [plan_type:Utf8, plan:Utf8] Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("EXPLAIN VERBOSE SELECT foo, f64_field FROM data"), @r###" + "#); + assert_snapshot!(plan("EXPLAIN VERBOSE SELECT foo, f64_field FROM data"), @r#" Explain [plan_type:Utf8, plan:Utf8] Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("EXPLAIN ANALYZE SELECT foo, f64_field FROM data"), @r###" + "#); + assert_snapshot!(plan("EXPLAIN ANALYZE SELECT foo, f64_field FROM data"), @r#" Analyze [plan_type:Utf8, plan:Utf8] Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("EXPLAIN ANALYZE VERBOSE SELECT foo, f64_field FROM data"), @r###" + "#); + assert_snapshot!(plan("EXPLAIN ANALYZE VERBOSE SELECT foo, f64_field FROM data"), @r#" Analyze [plan_type:Utf8, plan:Utf8] Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); } // TODO: make schema compatible. @@ -1989,153 +2006,153 @@ mod test { #[test] fn test_select_cast_postfix_operator() { // Float casting - assert_snapshot!(plan("SELECT f64_field::float FROM all_types"), @r###" + assert_snapshot!(plan("SELECT f64_field::float FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, all_types.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Float64;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT f64_field::unsigned FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT f64_field::unsigned FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:UInt64;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, CAST(all_types.f64_field AS UInt64) AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:UInt64;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT f64_field::integer FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT f64_field::integer FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Int64;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, CAST(all_types.f64_field AS Int64) AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Int64;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT f64_field::string FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT f64_field::string FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT f64_field::boolean FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT f64_field::boolean FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); + "#); // Integer casting - assert_snapshot!(plan("SELECT i64_field::float FROM all_types"), @r###" + assert_snapshot!(plan("SELECT i64_field::float FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:Float64;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, CAST(all_types.i64_field AS Float64) AS i64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:Float64;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT i64_field::unsigned FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT i64_field::unsigned FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:UInt64;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, CAST(all_types.i64_field AS UInt64) AS i64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:UInt64;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT i64_field::integer FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT i64_field::integer FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:Int64;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, all_types.i64_field AS i64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:Int64;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT i64_field::string FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT i64_field::string FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS i64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT i64_field::boolean FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT i64_field::boolean FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS i64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), i64_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); + "#); // Unsigned casting - assert_snapshot!(plan("SELECT u64_field::float FROM all_types"), @r###" + assert_snapshot!(plan("SELECT u64_field::float FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), u64_field:Float64;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, CAST(all_types.u64_field AS Float64) AS u64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), u64_field:Float64;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT u64_field::unsigned FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT u64_field::unsigned FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), u64_field:UInt64;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, all_types.u64_field AS u64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), u64_field:UInt64;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT u64_field::integer FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT u64_field::integer FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), u64_field:Int64;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, CAST(all_types.u64_field AS Int64) AS u64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), u64_field:Int64;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT u64_field::string FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT u64_field::string FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), u64_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS u64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), u64_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT u64_field::boolean FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT u64_field::boolean FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), u64_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS u64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), u64_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); + "#); // String casting - assert_snapshot!(plan("SELECT str_field::float FROM all_types"), @r###" + assert_snapshot!(plan("SELECT str_field::float FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS str_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT str_field::unsigned FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT str_field::unsigned FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS str_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT str_field::integer FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT str_field::integer FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS str_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT str_field::string FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT str_field::string FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Utf8;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, all_types.str_field AS str_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Utf8;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT str_field::boolean FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT str_field::boolean FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS str_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), str_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); + "#); // Boolean casting - assert_snapshot!(plan("SELECT bool_field::float FROM all_types"), @r###" + assert_snapshot!(plan("SELECT bool_field::float FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS bool_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT bool_field::unsigned FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT bool_field::unsigned FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS bool_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT bool_field::integer FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT bool_field::integer FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS bool_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT bool_field::string FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT bool_field::string FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS bool_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); - assert_snapshot!(plan("SELECT bool_field::boolean FROM all_types"), @r###" + "#); + assert_snapshot!(plan("SELECT bool_field::boolean FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Boolean;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, all_types.bool_field AS bool_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), bool_field:Boolean;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); + "#); // Validate various projection expressions with casts - assert_snapshot!(plan("SELECT f64_field::integer + i64_field + u64_field::integer FROM all_types"), @r###" + assert_snapshot!(plan("SELECT f64_field::integer + i64_field + u64_field::integer FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field_i64_field_u64_field:Int64;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, CAST(all_types.f64_field AS Int64) + all_types.i64_field + CAST(all_types.u64_field AS Int64) AS f64_field_i64_field_u64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field_i64_field_u64_field:Int64;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); + "#); - assert_snapshot!(plan("SELECT f64_field::integer + i64_field + str_field::integer FROM all_types"), @r###" + assert_snapshot!(plan("SELECT f64_field::integer + i64_field + str_field::integer FROM all_types"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field_i64_field_str_field:Null;N] Projection: Dictionary(Int32, Utf8("all_types")) AS iox::measurement, all_types.time AS time, NULL AS f64_field_i64_field_str_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field_i64_field_str_field:Null;N] TableScan: all_types [bool_field:Boolean;N, f64_field:Float64;N, i64_field:Int64;N, str_field:Utf8;N, tag0:Dictionary(Int32, Utf8);N, tag1:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), u64_field:UInt64;N] - "###); + "#); } } @@ -2150,72 +2167,72 @@ mod test { #[ignore = "incompatible schema with CeresDB"] #[test] fn no_group_by() { - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), count:Int64;N] Aggregate: groupBy=[[]], aggr=[[COUNT(data.f64_field)]] [COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY non_existent"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY non_existent"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), non_existent:Null;N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, NULL AS non_existent, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), non_existent:Null;N, count:Int64;N] Aggregate: groupBy=[[]], aggr=[[COUNT(data.f64_field)]] [COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY foo"), @r###" + "#); + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY foo"), @r#" Sort: foo ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, data.foo AS foo, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N] Aggregate: groupBy=[[data.foo]], aggr=[[COUNT(data.f64_field)]] [foo:Dictionary(Int32, Utf8);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // The `COUNT(f64_field)` aggregate is only projected ones in the Aggregate and reused in the projection - assert_snapshot!(plan("SELECT COUNT(f64_field), COUNT(f64_field) + COUNT(f64_field), COUNT(f64_field) * 3 FROM data"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field), COUNT(f64_field) + COUNT(f64_field), COUNT(f64_field) * 3 FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), count:Int64;N, count_f64_field_count_f64_field:Int64;N, count_f64_field:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, COUNT(data.f64_field) AS count, COUNT(data.f64_field) + COUNT(data.f64_field) AS count_f64_field_count_f64_field, COUNT(data.f64_field) * Int64(3) AS count_f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), count:Int64;N, count_f64_field_count_f64_field:Int64;N, count_f64_field:Int64;N] Aggregate: groupBy=[[]], aggr=[[COUNT(data.f64_field)]] [COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // non-existent tags are excluded from the Aggregate groupBy and Sort operators - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY foo, non_existent"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY foo, non_existent"), @r#" Sort: foo ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, non_existent:Null;N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, data.foo AS foo, NULL AS non_existent, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, non_existent:Null;N, count:Int64;N] Aggregate: groupBy=[[data.foo]], aggr=[[COUNT(data.f64_field)]] [foo:Dictionary(Int32, Utf8);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // Aggregate expression is projected once and reused in final projection - assert_snapshot!(plan("SELECT COUNT(f64_field), COUNT(f64_field) * 2 FROM data"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field), COUNT(f64_field) * 2 FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), count:Int64;N, count_f64_field:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, COUNT(data.f64_field) AS count, COUNT(data.f64_field) * Int64(2) AS count_f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), count:Int64;N, count_f64_field:Int64;N] Aggregate: groupBy=[[]], aggr=[[COUNT(data.f64_field)]] [COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // Aggregate expression selecting non-existent field - assert_snapshot!(plan("SELECT MEAN(f64_field) + MEAN(non_existent) FROM data"), @r###" + assert_snapshot!(plan("SELECT MEAN(f64_field) + MEAN(non_existent) FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), mean_f64_field_mean_non_existent:Null;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, NULL AS mean_f64_field_mean_non_existent [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), mean_f64_field_mean_non_existent:Null;N] EmptyRelation [] - "###); + "#); // Aggregate expression with GROUP BY and non-existent field - assert_snapshot!(plan("SELECT MEAN(f64_field) + MEAN(non_existent) FROM data GROUP BY foo"), @r###" + assert_snapshot!(plan("SELECT MEAN(f64_field) + MEAN(non_existent) FROM data GROUP BY foo"), @r#" Sort: foo ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, mean_f64_field_mean_non_existent:Null;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, data.foo AS foo, NULL AS mean_f64_field_mean_non_existent [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, mean_f64_field_mean_non_existent:Null;N] Aggregate: groupBy=[[data.foo]], aggr=[[]] [foo:Dictionary(Int32, Utf8);N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // Aggregate expression selecting tag, should treat as non-existent - assert_snapshot!(plan("SELECT MEAN(f64_field), MEAN(f64_field) + MEAN(non_existent) FROM data"), @r###" + assert_snapshot!(plan("SELECT MEAN(f64_field), MEAN(f64_field) + MEAN(non_existent) FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), mean:Float64;N, mean_f64_field_mean_non_existent:Null;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, AVG(data.f64_field) AS mean, NULL AS mean_f64_field_mean_non_existent [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), mean:Float64;N, mean_f64_field_mean_non_existent:Null;N] Aggregate: groupBy=[[]], aggr=[[AVG(data.f64_field)]] [AVG(data.f64_field):Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // Fallible @@ -2228,20 +2245,20 @@ mod test { #[ignore = "incompatible schema with CeresDB"] #[test] fn group_by_time() { - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s) FILL(none)"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s) FILL(none)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // supports offset parameter - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s, 5s) FILL(none)"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s, 5s) FILL(none)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(5000000000, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); } // TODO: make schema compatible. @@ -2249,96 +2266,96 @@ mod test { #[test] fn group_by_time_gapfill() { // No time bounds - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s)"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] GapFill: groupBy=[[time]], aggr=[[COUNT(data.f64_field)]], time_column=time, stride=IntervalDayTime("10000"), range=Unbounded..Excluded(now()) [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // No lower time bounds - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data WHERE time < '2022-10-31T02:02:00Z' GROUP BY TIME(10s)"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data WHERE time < '2022-10-31T02:02:00Z' GROUP BY TIME(10s)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] GapFill: groupBy=[[time]], aggr=[[COUNT(data.f64_field)]], time_column=time, stride=IntervalDayTime("10000"), range=Unbounded..Excluded(TimestampNanosecond(1667181720000000000, None)) [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Filter: data.time < TimestampNanosecond(1667181720000000000, None) [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // No upper time bounds - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data WHERE time >= '2022-10-31T02:00:00Z' GROUP BY TIME(10s)"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data WHERE time >= '2022-10-31T02:00:00Z' GROUP BY TIME(10s)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] GapFill: groupBy=[[time]], aggr=[[COUNT(data.f64_field)]], time_column=time, stride=IntervalDayTime("10000"), range=Included(TimestampNanosecond(1667181600000000000, None))..Excluded(now()) [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Filter: data.time >= TimestampNanosecond(1667181600000000000, None) [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // Default is FILL(null) - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data WHERE time >= '2022-10-31T02:00:00Z' AND time < '2022-10-31T02:02:00Z' GROUP BY TIME(10s)"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data WHERE time >= '2022-10-31T02:00:00Z' AND time < '2022-10-31T02:02:00Z' GROUP BY TIME(10s)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] GapFill: groupBy=[[time]], aggr=[[COUNT(data.f64_field)]], time_column=time, stride=IntervalDayTime("10000"), range=Included(TimestampNanosecond(1667181600000000000, None))..Excluded(TimestampNanosecond(1667181720000000000, None)) [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Filter: data.time >= TimestampNanosecond(1667181600000000000, None) AND data.time < TimestampNanosecond(1667181720000000000, None) [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s)"), @r###" + "#); + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] GapFill: groupBy=[[time]], aggr=[[COUNT(data.f64_field)]], time_column=time, stride=IntervalDayTime("10000"), range=Unbounded..Excluded(now()) [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s) FILL(null)"), @r###" + "#); + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s) FILL(null)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] GapFill: groupBy=[[time]], aggr=[[COUNT(data.f64_field)]], time_column=time, stride=IntervalDayTime("10000"), range=Unbounded..Excluded(now()) [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s) FILL(previous)"), @r###" + "#); + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s) FILL(previous)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] GapFill: groupBy=[[time]], aggr=[[LOCF(COUNT(data.f64_field))]], time_column=time, stride=IntervalDayTime("10000"), range=Unbounded..Excluded(now()) [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s) FILL(0)"), @r###" + "#); + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s) FILL(0)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, coalesce(COUNT(data.f64_field), Int64(0)) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] GapFill: groupBy=[[time]], aggr=[[COUNT(data.f64_field)]], time_column=time, stride=IntervalDayTime("10000"), range=Unbounded..Excluded(now()) [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // Coalesces the fill value, which is a float, to the matching type of a `COUNT` aggregate. - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s) FILL(3.2)"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY TIME(10s) FILL(3.2)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, coalesce(COUNT(data.f64_field), Int64(3)) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count:Int64;N] GapFill: groupBy=[[time]], aggr=[[COUNT(data.f64_field)]], time_column=time, stride=IntervalDayTime("10000"), range=Unbounded..Excluded(now()) [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // Aggregates as part of a binary expression - assert_snapshot!(plan("SELECT COUNT(f64_field) + MEAN(f64_field) FROM data GROUP BY TIME(10s) FILL(3.2)"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) + MEAN(f64_field) FROM data GROUP BY TIME(10s) FILL(3.2)"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count_f64_field_mean_f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, time, coalesce(COUNT(data.f64_field), Int64(3)) + coalesce(AVG(data.f64_field), Float64(3.2)) AS count_f64_field_mean_f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None);N, count_f64_field_mean_f64_field:Float64;N] GapFill: groupBy=[[time]], aggr=[[COUNT(data.f64_field), AVG(data.f64_field)]], time_column=time, stride=IntervalDayTime("10000"), range=Unbounded..Excluded(now()) [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N, AVG(data.f64_field):Float64;N] Aggregate: groupBy=[[datebin(IntervalDayTime("10000"), data.time, TimestampNanosecond(0, None)) AS time]], aggr=[[COUNT(data.f64_field), AVG(data.f64_field)]] [time:Timestamp(Nanosecond, None);N, COUNT(data.f64_field):Int64;N, AVG(data.f64_field):Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); } // TODO: make schema compatible. #[ignore = "incompatible schema with CeresDB"] #[test] fn with_limit_or_offset() { - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY foo LIMIT 1"), @r###" + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY foo LIMIT 1"), @r#" Projection: iox::measurement, time, foo, count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N] Filter: iox::row <= Int64(1) [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N, iox::row:UInt64;N] WindowAggr: windowExpr=[[ROW_NUMBER() PARTITION BY [foo] ORDER BY [time ASC NULLS LAST] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW AS iox::row]] [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N, iox::row:UInt64;N] @@ -2346,8 +2363,8 @@ mod test { Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, data.foo AS foo, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N] Aggregate: groupBy=[[data.foo]], aggr=[[COUNT(data.f64_field)]] [foo:Dictionary(Int32, Utf8);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY foo OFFSET 1"), @r###" + "#); + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY foo OFFSET 1"), @r#" Projection: iox::measurement, time, foo, count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N] Filter: iox::row > Int64(1) [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N, iox::row:UInt64;N] WindowAggr: windowExpr=[[ROW_NUMBER() PARTITION BY [foo] ORDER BY [time ASC NULLS LAST] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW AS iox::row]] [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N, iox::row:UInt64;N] @@ -2355,8 +2372,8 @@ mod test { Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, data.foo AS foo, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N] Aggregate: groupBy=[[data.foo]], aggr=[[COUNT(data.f64_field)]] [foo:Dictionary(Int32, Utf8);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY foo LIMIT 2 OFFSET 3"), @r###" + "#); + assert_snapshot!(plan("SELECT COUNT(f64_field) FROM data GROUP BY foo LIMIT 2 OFFSET 3"), @r#" Projection: iox::measurement, time, foo, count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N] Filter: iox::row BETWEEN Int64(4) AND Int64(5) [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N, iox::row:UInt64;N] WindowAggr: windowExpr=[[ROW_NUMBER() PARTITION BY [foo] ORDER BY [time ASC NULLS LAST] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW AS iox::row]] [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N, iox::row:UInt64;N] @@ -2364,7 +2381,7 @@ mod test { Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, TimestampNanosecond(0, None) AS time, data.foo AS foo, COUNT(data.f64_field) AS count [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, count:Int64;N] Aggregate: groupBy=[[data.foo]], aggr=[[COUNT(data.f64_field)]] [foo:Dictionary(Int32, Utf8);N, COUNT(data.f64_field):Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); // Fallible @@ -2408,47 +2425,47 @@ mod test { #[ignore = "incompatible schema with CeresDB"] #[test] fn test_single_measurement() { - assert_snapshot!(plan("SELECT f64_field FROM data"), @r###" + assert_snapshot!(plan("SELECT f64_field FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT time, f64_field FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT time, f64_field FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT time as timestamp, f64_field FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT time as timestamp, f64_field FROM data"), @r#" Projection: iox::measurement, timestamp, f64_field [iox::measurement:Dictionary(Int32, Utf8), timestamp:Timestamp(Nanosecond, None), f64_field:Float64;N] Sort: data.time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), timestamp:Timestamp(Nanosecond, None), f64_field:Float64;N, time:Timestamp(Nanosecond, None)] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS timestamp, data.f64_field AS f64_field, data.time [iox::measurement:Dictionary(Int32, Utf8), timestamp:Timestamp(Nanosecond, None), f64_field:Float64;N, time:Timestamp(Nanosecond, None)] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT foo, f64_field FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT foo, f64_field FROM data"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT foo, f64_field, i64_field FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT foo, f64_field, i64_field FROM data"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N, i64_field:Int64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field AS f64_field, data.i64_field AS i64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N, i64_field:Int64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT /^f/ FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT /^f/ FROM data"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.f64_field AS f64_field, data.foo AS foo [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT * FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT * FROM data"), @r#" Sort: time ASC NULLS LAST, bar ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, with space:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.TIME AS TIME, data.bar AS bar, data.bool_field AS bool_field, data.f64_field AS f64_field, data.foo AS foo, data.i64_field AS i64_field, data.mixedCase AS mixedCase, data.str_field AS str_field, data.with space AS with space [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, with space:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT TIME FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT TIME FROM data"), @r#" Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), TIME:Boolean;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.TIME AS TIME [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), TIME:Boolean;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); // TIME is a field + "#); // TIME is a field } /// Arithmetic expressions in the projection list @@ -2456,26 +2473,26 @@ mod test { #[ignore = "incompatible schema with CeresDB"] #[test] fn test_simple_arithmetic_in_projection() { - assert_snapshot!(plan("SELECT foo, f64_field + f64_field FROM data"), @r###" + assert_snapshot!(plan("SELECT foo, f64_field + f64_field FROM data"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field_f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field + data.f64_field AS f64_field_f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field_f64_field:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT foo, sin(f64_field) FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT foo, sin(f64_field) FROM data"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, sin:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, sin(data.f64_field) AS sin [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, sin:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT foo, atan2(f64_field, 2) FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT foo, atan2(f64_field, 2) FROM data"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, atan2:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, atan2(data.f64_field, Int64(2)) AS atan2 [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, atan2:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); - assert_snapshot!(plan("SELECT foo, f64_field + 0.5 FROM data"), @r###" + "#); + assert_snapshot!(plan("SELECT foo, f64_field + 0.5 FROM data"), @r#" Sort: time ASC NULLS LAST, foo ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] Projection: Dictionary(Int32, Utf8("data")) AS iox::measurement, data.time AS time, data.foo AS foo, data.f64_field + Float64(0.5) AS f64_field [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), foo:Dictionary(Int32, Utf8);N, f64_field:Float64;N] TableScan: data [TIME:Boolean;N, bar:Dictionary(Int32, Utf8);N, bool_field:Boolean;N, f64_field:Float64;N, foo:Dictionary(Int32, Utf8);N, i64_field:Int64;N, mixedCase:Float64;N, str_field:Utf8;N, time:Timestamp(Nanosecond, None), with space:Float64;N] - "###); + "#); } // TODO: make schema compatible. @@ -2483,60 +2500,60 @@ mod test { #[test] fn test_select_single_measurement_group_by() { // Sort should be cpu, time - assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu"), @r###" + assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu"), @r#" Sort: cpu ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.cpu AS cpu, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); // Sort should be cpu, time - assert_snapshot!(plan("SELECT cpu, usage_idle FROM cpu GROUP BY cpu"), @r###" + assert_snapshot!(plan("SELECT cpu, usage_idle FROM cpu GROUP BY cpu"), @r#" Sort: cpu ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.cpu AS cpu, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); // Sort should be cpu, region, time - assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu, region"), @r###" + assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu, region"), @r#" Sort: cpu ASC NULLS LAST, region ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.cpu AS cpu, cpu.region AS region, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); // Sort should be cpu, region, time - assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY region, cpu"), @r###" + assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY region, cpu"), @r#" Sort: cpu ASC NULLS LAST, region ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.cpu AS cpu, cpu.region AS region, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); // Sort should be cpu, time, region - assert_snapshot!(plan("SELECT region, usage_idle FROM cpu GROUP BY cpu"), @r###" + assert_snapshot!(plan("SELECT region, usage_idle FROM cpu GROUP BY cpu"), @r#" Sort: cpu ASC NULLS LAST, time ASC NULLS LAST, region ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.cpu AS cpu, cpu.region AS region, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); // If a tag specified in a GROUP BY does not exist in the measurement, it should be omitted from the sort - assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu, non_existent"), @r###" + assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu, non_existent"), @r#" Sort: cpu ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, non_existent:Null;N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.cpu AS cpu, NULL AS non_existent, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, non_existent:Null;N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); // If a tag specified in a projection does not exist in the measurement, it should be omitted from the sort - assert_snapshot!(plan("SELECT usage_idle, cpu, non_existent FROM cpu GROUP BY cpu"), @r###" + assert_snapshot!(plan("SELECT usage_idle, cpu, non_existent FROM cpu GROUP BY cpu"), @r#" Sort: cpu ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), usage_idle:Float64;N, cpu:Dictionary(Int32, Utf8);N, non_existent:Null;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.usage_idle AS usage_idle, cpu.cpu AS cpu, NULL AS non_existent [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), usage_idle:Float64;N, cpu:Dictionary(Int32, Utf8);N, non_existent:Null;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); // If a non-existent field is included in the GROUP BY and projection, it should not be duplicated - assert_snapshot!(plan("SELECT usage_idle, non_existent FROM cpu GROUP BY cpu, non_existent"), @r###" + assert_snapshot!(plan("SELECT usage_idle, non_existent FROM cpu GROUP BY cpu, non_existent"), @r#" Sort: cpu ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N, non_existent:Null;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.cpu AS cpu, cpu.usage_idle AS usage_idle, NULL AS non_existent [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N, non_existent:Null;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); } // TODO: make schema compatible. @@ -2544,7 +2561,7 @@ mod test { #[test] fn test_select_multiple_measurements_group_by() { // Sort should be iox::measurement, cpu, time - assert_snapshot!(plan("SELECT usage_idle, bytes_free FROM cpu, disk GROUP BY cpu"), @r###" + assert_snapshot!(plan("SELECT usage_idle, bytes_free FROM cpu, disk GROUP BY cpu"), @r#" Sort: iox::measurement ASC NULLS LAST, cpu ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Union [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Projection: iox::measurement, time, CAST(cpu AS Utf8) AS cpu, usage_idle, CAST(bytes_free AS Int64) AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] @@ -2555,10 +2572,10 @@ mod test { Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Null;N, usage_idle:Null;N, bytes_free:Int64;N] Projection: Dictionary(Int32, Utf8("disk")) AS iox::measurement, disk.time AS time, NULL AS cpu, NULL AS usage_idle, disk.bytes_free AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Null;N, usage_idle:Null;N, bytes_free:Int64;N] TableScan: disk [bytes_free:Int64;N, bytes_used:Int64;N, device:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None)] - "###); + "#); // Sort should be iox::measurement, cpu, device, time - assert_snapshot!(plan("SELECT usage_idle, bytes_free FROM cpu, disk GROUP BY device, cpu"), @r###" + assert_snapshot!(plan("SELECT usage_idle, bytes_free FROM cpu, disk GROUP BY device, cpu"), @r#" Sort: iox::measurement ASC NULLS LAST, cpu ASC NULLS LAST, device ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Utf8;N, device:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Union [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Utf8;N, device:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Projection: iox::measurement, time, CAST(cpu AS Utf8) AS cpu, CAST(device AS Utf8) AS device, usage_idle, CAST(bytes_free AS Int64) AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Utf8;N, device:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] @@ -2569,10 +2586,10 @@ mod test { Sort: device ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Null;N, device:Dictionary(Int32, Utf8);N, usage_idle:Null;N, bytes_free:Int64;N] Projection: Dictionary(Int32, Utf8("disk")) AS iox::measurement, disk.time AS time, NULL AS cpu, disk.device AS device, NULL AS usage_idle, disk.bytes_free AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Null;N, device:Dictionary(Int32, Utf8);N, usage_idle:Null;N, bytes_free:Int64;N] TableScan: disk [bytes_free:Int64;N, bytes_used:Int64;N, device:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None)] - "###); + "#); // Sort should be iox::measurement, cpu, time, device - assert_snapshot!(plan("SELECT device, usage_idle, bytes_free FROM cpu, disk GROUP BY cpu"), @r###" + assert_snapshot!(plan("SELECT device, usage_idle, bytes_free FROM cpu, disk GROUP BY cpu"), @r#" Sort: iox::measurement ASC NULLS LAST, cpu ASC NULLS LAST, time ASC NULLS LAST, device ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Utf8;N, device:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Union [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Utf8;N, device:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Projection: iox::measurement, time, CAST(cpu AS Utf8) AS cpu, CAST(device AS Utf8) AS device, usage_idle, CAST(bytes_free AS Int64) AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Utf8;N, device:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] @@ -2583,10 +2600,10 @@ mod test { Sort: time ASC NULLS LAST, device ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Null;N, device:Dictionary(Int32, Utf8);N, usage_idle:Null;N, bytes_free:Int64;N] Projection: Dictionary(Int32, Utf8("disk")) AS iox::measurement, disk.time AS time, NULL AS cpu, disk.device AS device, NULL AS usage_idle, disk.bytes_free AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Null;N, device:Dictionary(Int32, Utf8);N, usage_idle:Null;N, bytes_free:Int64;N] TableScan: disk [bytes_free:Int64;N, bytes_used:Int64;N, device:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None)] - "###); + "#); // Sort should be iox::measurement, cpu, device, time - assert_snapshot!(plan("SELECT cpu, usage_idle, bytes_free FROM cpu, disk GROUP BY cpu, device"), @r###" + assert_snapshot!(plan("SELECT cpu, usage_idle, bytes_free FROM cpu, disk GROUP BY cpu, device"), @r#" Sort: iox::measurement ASC NULLS LAST, cpu ASC NULLS LAST, device ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Union [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Projection: iox::measurement, time, CAST(device AS Utf8) AS device, CAST(cpu AS Utf8) AS cpu, usage_idle, CAST(bytes_free AS Int64) AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] @@ -2597,10 +2614,10 @@ mod test { Sort: device ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Dictionary(Int32, Utf8);N, cpu:Null;N, usage_idle:Null;N, bytes_free:Int64;N] Projection: Dictionary(Int32, Utf8("disk")) AS iox::measurement, disk.time AS time, disk.device AS device, NULL AS cpu, NULL AS usage_idle, disk.bytes_free AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Dictionary(Int32, Utf8);N, cpu:Null;N, usage_idle:Null;N, bytes_free:Int64;N] TableScan: disk [bytes_free:Int64;N, bytes_used:Int64;N, device:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None)] - "###); + "#); // Sort should be iox::measurement, device, time, cpu - assert_snapshot!(plan("SELECT cpu, usage_idle, bytes_free FROM cpu, disk GROUP BY device"), @r###" + assert_snapshot!(plan("SELECT cpu, usage_idle, bytes_free FROM cpu, disk GROUP BY device"), @r#" Sort: iox::measurement ASC NULLS LAST, device ASC NULLS LAST, time ASC NULLS LAST, cpu ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Union [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Projection: iox::measurement, time, CAST(device AS Utf8) AS device, CAST(cpu AS Utf8) AS cpu, usage_idle, CAST(bytes_free AS Int64) AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] @@ -2611,10 +2628,10 @@ mod test { Sort: device ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Dictionary(Int32, Utf8);N, cpu:Null;N, usage_idle:Null;N, bytes_free:Int64;N] Projection: Dictionary(Int32, Utf8("disk")) AS iox::measurement, disk.time AS time, disk.device AS device, NULL AS cpu, NULL AS usage_idle, disk.bytes_free AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Dictionary(Int32, Utf8);N, cpu:Null;N, usage_idle:Null;N, bytes_free:Int64;N] TableScan: disk [bytes_free:Int64;N, bytes_used:Int64;N, device:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None)] - "###); + "#); // If a tag specified in a GROUP BY does not exist across all measurements, it should be omitted from the sort - assert_snapshot!(plan("SELECT cpu, usage_idle, bytes_free FROM cpu, disk GROUP BY device, non_existent"), @r###" + assert_snapshot!(plan("SELECT cpu, usage_idle, bytes_free FROM cpu, disk GROUP BY device, non_existent"), @r#" Sort: iox::measurement ASC NULLS LAST, device ASC NULLS LAST, time ASC NULLS LAST, cpu ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, non_existent:Null;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Union [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, non_existent:Null;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] Projection: iox::measurement, time, CAST(device AS Utf8) AS device, non_existent, CAST(cpu AS Utf8) AS cpu, usage_idle, CAST(bytes_free AS Int64) AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, non_existent:Null;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N] @@ -2625,10 +2642,10 @@ mod test { Sort: device ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Dictionary(Int32, Utf8);N, non_existent:Null;N, cpu:Null;N, usage_idle:Null;N, bytes_free:Int64;N] Projection: Dictionary(Int32, Utf8("disk")) AS iox::measurement, disk.time AS time, disk.device AS device, NULL AS non_existent, NULL AS cpu, NULL AS usage_idle, disk.bytes_free AS bytes_free [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Dictionary(Int32, Utf8);N, non_existent:Null;N, cpu:Null;N, usage_idle:Null;N, bytes_free:Int64;N] TableScan: disk [bytes_free:Int64;N, bytes_used:Int64;N, device:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None)] - "###); + "#); // If a tag specified in a projection does not exist across all measurements, it should be omitted from the sort - assert_snapshot!(plan("SELECT cpu, usage_idle, bytes_free, non_existent FROM cpu, disk GROUP BY device"), @r###" + assert_snapshot!(plan("SELECT cpu, usage_idle, bytes_free, non_existent FROM cpu, disk GROUP BY device"), @r#" Sort: iox::measurement ASC NULLS LAST, device ASC NULLS LAST, time ASC NULLS LAST, cpu ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N, non_existent:Null;N] Union [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N, non_existent:Null;N] Projection: iox::measurement, time, CAST(device AS Utf8) AS device, CAST(cpu AS Utf8) AS cpu, usage_idle, CAST(bytes_free AS Int64) AS bytes_free, non_existent [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Utf8;N, cpu:Utf8;N, usage_idle:Float64;N, bytes_free:Int64;N, non_existent:Null;N] @@ -2639,37 +2656,37 @@ mod test { Sort: device ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Dictionary(Int32, Utf8);N, cpu:Null;N, usage_idle:Null;N, bytes_free:Int64;N, non_existent:Null;N] Projection: Dictionary(Int32, Utf8("disk")) AS iox::measurement, disk.time AS time, disk.device AS device, NULL AS cpu, NULL AS usage_idle, disk.bytes_free AS bytes_free, NULL AS non_existent [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), device:Dictionary(Int32, Utf8);N, cpu:Null;N, usage_idle:Null;N, bytes_free:Int64;N, non_existent:Null;N] TableScan: disk [bytes_free:Int64;N, bytes_used:Int64;N, device:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None)] - "###); + "#); } // TODO: make schema compatible. #[ignore = "incompatible schema with CeresDB"] #[test] fn test_select_group_by_limit_offset() { - assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu LIMIT 1"), @r###" + assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu LIMIT 1"), @r#" Projection: iox::measurement, time, cpu, usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Filter: iox::row <= Int64(1) [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N, iox::row:UInt64;N] WindowAggr: windowExpr=[[ROW_NUMBER() PARTITION BY [cpu] ORDER BY [time ASC NULLS LAST] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW AS iox::row]] [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N, iox::row:UInt64;N] Sort: cpu ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.cpu AS cpu, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); - assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu OFFSET 1"), @r###" + "#); + assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu OFFSET 1"), @r#" Projection: iox::measurement, time, cpu, usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Filter: iox::row > Int64(1) [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N, iox::row:UInt64;N] WindowAggr: windowExpr=[[ROW_NUMBER() PARTITION BY [cpu] ORDER BY [time ASC NULLS LAST] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW AS iox::row]] [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N, iox::row:UInt64;N] Sort: cpu ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.cpu AS cpu, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); - assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu LIMIT 1 OFFSET 1"), @r###" + "#); + assert_snapshot!(plan("SELECT usage_idle FROM cpu GROUP BY cpu LIMIT 1 OFFSET 1"), @r#" Projection: iox::measurement, time, cpu, usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Filter: iox::row BETWEEN Int64(2) AND Int64(2) [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N, iox::row:UInt64;N] WindowAggr: windowExpr=[[ROW_NUMBER() PARTITION BY [cpu] ORDER BY [time ASC NULLS LAST] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW AS iox::row]] [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N, iox::row:UInt64;N] Sort: cpu ASC NULLS LAST, time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, cpu.cpu AS cpu, cpu.usage_idle AS usage_idle [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), cpu:Dictionary(Int32, Utf8);N, usage_idle:Float64;N] TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] - "###); + "#); } // The following is an outline of additional scenarios to develop diff --git a/iox_query_influxql/src/plan/planner_time_range_expression.rs b/iox_query_influxql/src/plan/planner_time_range_expression.rs index dcf7a95..b0edcde 100644 --- a/iox_query_influxql/src/plan/planner_time_range_expression.rs +++ b/iox_query_influxql/src/plan/planner_time_range_expression.rs @@ -143,7 +143,7 @@ fn reduce_expr(expr: &Expr, tz: Option) -> ExprResult { Literal::Float(v) => Ok(lit(*v)), Literal::String(v) => Ok(lit(v.clone())), Literal::Timestamp(v) => Ok(lit(ScalarValue::TimestampNanosecond( - Some(v.timestamp_nanos()), + v.timestamp_nanos_opt(), None, ))), Literal::Duration(v) => Ok(lit(ScalarValue::new_interval_mdn(0, 0, **v))), @@ -415,7 +415,7 @@ fn reduce_binary_lhs_string_df_expr( fn parse_timestamp_nanos(s: &str, tz: Option) -> Result { parse_timestamp(s, tz) - .map(|ts| ts.timestamp_nanos()) + .map(|ts| ts.timestamp_nanos_opt().unwrap()) .map_err(|_| DataFusionError::Plan(format!("'{s}' is not a valid timestamp"))) } diff --git a/iox_query_influxql/src/plan/rewriter.rs b/iox_query_influxql/src/plan/rewriter.rs index 0304b00..f2a5f76 100644 --- a/iox_query_influxql/src/plan/rewriter.rs +++ b/iox_query_influxql/src/plan/rewriter.rs @@ -22,7 +22,7 @@ use std::ops::{ControlFlow, Deref}; /// Recursively expand the `from` clause of `stmt` and any subqueries. fn rewrite_from(s: &dyn SchemaProvider, stmt: &mut SelectStatement) -> Result<()> { let mut new_from = Vec::new(); - for ms in stmt.from.iter() { + for ms in &*stmt.from { match ms { MeasurementSelection::Name(qmn) => match qmn { QualifiedMeasurementName { @@ -97,7 +97,7 @@ fn from_field_and_dimensions( ts.extend(tag_set); } MeasurementSelection::Subquery(select) => { - for f in select.fields.iter() { + for f in &*select.fields { let dt = match evaluate_type(s, &f.expr, &select.from)? { Some(dt) => dt, None => continue, @@ -189,7 +189,7 @@ fn has_wildcards(stmt: &SelectStatement) -> (bool, bool) { /// Derived from [Go implementation](https://github.com/influxdata/influxql/blob/1ba470371ec093d57a726b143fe6ccbacf1b452b/ast.go#L1185). fn rewrite_field_list(s: &dyn SchemaProvider, stmt: &mut SelectStatement) -> Result<()> { // Iterate through the `FROM` clause and rewrite any subqueries first. - for ms in stmt.from.iter_mut() { + for ms in &mut *stmt.from { if let MeasurementSelection::Subquery(subquery) = ms { rewrite_field_list(s, subquery)?; } @@ -258,7 +258,7 @@ fn rewrite_field_list(s: &dyn SchemaProvider, stmt: &mut SelectStatement) -> Res if has_field_wildcard { let mut new_fields = Vec::new(); - for f in stmt.fields.iter() { + for f in &*stmt.fields { let add_field = |f: &VarRef| { new_fields.push(Field { expr: Expr::VarRef(f.clone()), diff --git a/iox_query_influxql/src/plan/timestamp.rs b/iox_query_influxql/src/plan/timestamp.rs index 0776413..b4be1bd 100644 --- a/iox_query_influxql/src/plan/timestamp.rs +++ b/iox_query_influxql/src/plan/timestamp.rs @@ -1,6 +1,5 @@ use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Offset, TimeZone}; use datafusion::common::{DataFusionError, Result}; - /// Parse the timestamp string and return a DateTime in UTC. fn parse_timestamp_utc(s: &str) -> Result> { // 1a. Try a date time format string with nanosecond precision and then without @@ -18,7 +17,7 @@ fn parse_timestamp_utc(s: &str) -> Result> { NaiveDate::parse_from_str(s, "%Y-%m-%d") .map(|nd| nd.and_time(NaiveTime::default())), ) - .map(|ts| DateTime::from_utc(ts, chrono::Utc.fix())) + .map(|ts| DateTime::from_naive_utc_and_offset(ts, chrono::Utc.fix())) .map_err(|_| DataFusionError::Plan("invalid timestamp string".into())) } @@ -26,6 +25,7 @@ fn parse_timestamp_utc(s: &str) -> Result> { fn parse_timestamp_tz(s: &str, tz: chrono_tz::Tz) -> Result> { // 1a. Try a date time format string with nanosecond precision // https://github.com/influxdata/influxql/blob/1ba470371ec093d57a726b143fe6ccbacf1b452b/ast.go#L3661 + #[allow(deprecated)] tz.datetime_from_str(s, "%Y-%m-%d %H:%M:%S%.f") // 1a. Try a date time format string without nanosecond precision .or_else(|_| tz.datetime_from_str(s, "%Y-%m-%d %H:%M:%S")) diff --git a/iox_query_influxql/src/plan/util_copy.rs b/iox_query_influxql/src/plan/util_copy.rs index b88582f..98b7eac 100644 --- a/iox_query_influxql/src/plan/util_copy.rs +++ b/iox_query_influxql/src/plan/util_copy.rs @@ -9,7 +9,7 @@ //! NOTE use datafusion::common::{DataFusionError, Result}; use datafusion::logical_expr::expr::{ - AggregateUDF, Alias, InList, InSubquery, Placeholder, ScalarFunction, ScalarUDF, + AggregateUDF, Alias, InList, InSubquery, Placeholder, ScalarFunction, }; use datafusion::logical_expr::{ expr::{ @@ -59,15 +59,16 @@ where distinct, filter, order_by, - }) => Ok(Expr::AggregateFunction(AggregateFunction::new( - fun.clone(), - args.iter() + }) => Ok(Expr::AggregateFunction(AggregateFunction { + fun: fun.clone(), + args: args + .iter() .map(|e| clone_with_replacement(e, replacement_fn)) .collect::>>()?, - *distinct, - filter.clone(), - order_by.clone(), - ))), + distinct: *distinct, + filter: filter.clone(), + order_by: order_by.clone(), + })), Expr::WindowFunction(WindowFunction { fun, args, @@ -103,9 +104,14 @@ where filter: filter.clone(), order_by: order_by.clone(), })), - Expr::Alias(Alias { expr, name }) => Ok(Expr::Alias(Alias { + Expr::Alias(Alias { + expr, + name, + relation, + }) => Ok(Expr::Alias(Alias { expr: Box::new(clone_with_replacement(expr, replacement_fn)?), name: name.clone(), + relation: relation.clone(), })), Expr::Between(Between { expr, @@ -186,22 +192,15 @@ where None => None, }, ))), - Expr::ScalarFunction(ScalarFunction { fun, args }) => { + Expr::ScalarFunction(ScalarFunction { func_def, args }) => { Ok(Expr::ScalarFunction(ScalarFunction { - fun: fun.clone(), + func_def: func_def.clone(), args: args .iter() .map(|e| clone_with_replacement(e, replacement_fn)) .collect::>>()?, })) } - Expr::ScalarUDF(ScalarUDF { fun, args }) => Ok(Expr::ScalarUDF(ScalarUDF { - fun: fun.clone(), - args: args - .iter() - .map(|arg| clone_with_replacement(arg, replacement_fn)) - .collect::>>()?, - })), Expr::Negative(nested_expr) => Ok(Expr::Negative(Box::new( clone_with_replacement(nested_expr, replacement_fn)?, ))), @@ -271,12 +270,13 @@ where subquery: subquery.clone(), negated: *negated, })), - Expr::Wildcard => Ok(Expr::Wildcard), - Expr::QualifiedWildcard { .. } => Ok(expr.clone()), - Expr::GetIndexedField(GetIndexedField { key, expr }) => { + Expr::Wildcard { qualifier } => Ok(Expr::Wildcard { + qualifier: qualifier.clone(), + }), + Expr::GetIndexedField(GetIndexedField { expr, field }) => { Ok(Expr::GetIndexedField(GetIndexedField::new( Box::new(clone_with_replacement(expr.as_ref(), replacement_fn)?), - key.clone(), + field.clone(), ))) } Expr::GroupingSet(set) => match set { diff --git a/query_functions/src/regex.rs b/query_functions/src/regex.rs index 380312c..f153a43 100644 --- a/query_functions/src/regex.rs +++ b/query_functions/src/regex.rs @@ -357,22 +357,22 @@ mod test { fn test_clean_non_meta_escapes() { let cases = vec![ ("", ""), - (r#"\"#, r#"\"#), - (r#"\\"#, r#"\\"#), + (r"\", r"\"), + (r"\\", r"\\"), // : is not a special meta character - (r#"\:"#, r#":"#), + (r"\:", r#":"#), // . is a special meta character - (r#"\."#, r#"\."#), - (r#"foo\"#, r#"foo\"#), - (r#"foo\\"#, r#"foo\\"#), - (r#"foo\:"#, r#"foo:"#), - (r#"foo\xff"#, r#"foo\xff"#), - (r#"fo\\o"#, r#"fo\\o"#), - (r#"fo\:o"#, r#"fo:o"#), - (r#"fo\:o\x123"#, r#"fo:o\x123"#), - (r#"fo\:o\x123\:"#, r#"fo:o\x123:"#), - (r#"foo\\\:bar"#, r#"foo\\:bar"#), - (r#"foo\\\:bar\\\:"#, r#"foo\\:bar\\:"#), + (r"\.", r"\."), + (r"foo\", r"foo\"), + (r"foo\\", r"foo\\"), + (r"foo\:", r#"foo:"#), + (r"foo\xff", r"foo\xff"), + (r"fo\\o", r"fo\\o"), + (r"fo\:o", r#"fo:o"#), + (r"fo\:o\x123", r"fo:o\x123"), + (r"fo\:o\x123\:", r"fo:o\x123:"), + (r"foo\\\:bar", r"foo\\:bar"), + (r"foo\\\:bar\\\:", r"foo\\:bar\\:"), ("foo", "foo"), ]; diff --git a/query_functions/src/selectors/internal.rs b/query_functions/src/selectors/internal.rs index c2d9262..af66b97 100644 --- a/query_functions/src/selectors/internal.rs +++ b/query_functions/src/selectors/internal.rs @@ -109,8 +109,8 @@ impl ToState for &str { fn make_scalar_struct(data_fields: Vec) -> ScalarValue { let fields = vec![ - Field::new("value", data_fields[0].get_datatype(), true), - Field::new("time", data_fields[1].get_datatype(), true), + Field::new("value", data_fields[0].data_type(), true), + Field::new("time", data_fields[1].data_type(), true), ]; ScalarValue::Struct(Some(data_fields), Fields::from(fields)) diff --git a/query_functions/src/window/internal.rs b/query_functions/src/window/internal.rs index 8061507..7c08c4b 100644 --- a/query_functions/src/window/internal.rs +++ b/query_functions/src/window/internal.rs @@ -146,7 +146,7 @@ fn timestamp_to_datetime(ts: i64) -> DateTime { // Note that nsec as u32 is safe here because modulo on a negative ts value // still produces a positive remainder. let datetime = NaiveDateTime::from_timestamp_opt(secs, nsec as u32).expect("ts in range"); - DateTime::from_utc(datetime, Utc) + DateTime::from_naive_utc_and_offset(datetime, Utc) } /// Original: @@ -198,8 +198,8 @@ fn to_timestamp_nanos_utc( NaiveTime::from_hms_nano_opt(hour, min, sec, nano).expect("hour-min-sec-nano in range"); let ndatetime = NaiveDateTime::new(ndate, ntime); - let datetime = DateTime::::from_utc(ndatetime, Utc); - datetime.timestamp_nanos() + let datetime = DateTime::::from_naive_utc_and_offset(ndatetime, Utc); + datetime.timestamp_nanos_opt().unwrap() } impl Add for i64 { @@ -386,7 +386,7 @@ mod tests { /// t: mustParseTime("1970-02-01T00:00:00Z"), fn must_parse_time(s: &str) -> i64 { let datetime = DateTime::parse_from_rfc3339(s).unwrap(); - datetime.timestamp_nanos() + datetime.timestamp_nanos_opt().unwrap() } /// TestWindow_GetEarliestBounds diff --git a/rust-toolchain b/rust-toolchain index 3f36906..5f169ab 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2023-02-02 +nightly-2023-08-28 diff --git a/test_helpers/Cargo.toml b/test_helpers/Cargo.toml index 86bba9d..9b77324 100644 --- a/test_helpers/Cargo.toml +++ b/test_helpers/Cargo.toml @@ -12,7 +12,7 @@ tempfile = "3.4.0" tracing-log = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } observability_deps = { path = "../observability_deps" } -async-trait = { version = "0.1.66", optional = true } +async-trait = { version = "0.1.73", optional = true } tokio = { version = "1.26.0", optional = true, default_features = false, features = ["time"] } [features] diff --git a/test_helpers/src/timeout.rs b/test_helpers/src/timeout.rs index 7e4636e..6a29417 100644 --- a/test_helpers/src/timeout.rs +++ b/test_helpers/src/timeout.rs @@ -43,7 +43,7 @@ mod tests { #[should_panic(expected = "timeout")] async fn test_exceeded_panic() { let (_tx, rx) = oneshot::channel::<()>(); - let task = tokio::spawn(async move { rx.await }); + let task = tokio::spawn(rx); let _ = task.with_timeout_panic(Duration::from_millis(1)).await; } @@ -51,7 +51,7 @@ mod tests { #[tokio::test] async fn test_exceeded() { let (_tx, rx) = oneshot::channel::<()>(); - let task = tokio::spawn(async move { rx.await }); + let task = tokio::spawn(rx); let _ = task .with_timeout(Duration::from_millis(1))