diff --git a/src/sqllogictest/src/parser.rs b/src/sqllogictest/src/parser.rs index 8b703596028f8..c19f37f4bc726 100644 --- a/src/sqllogictest/src/parser.rs +++ b/src/sqllogictest/src/parser.rs @@ -252,13 +252,27 @@ impl<'a> Parser<'a> { static HASH_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"(\S+) values hashing to (\S+)").unwrap()); let sql = self.split_at(&QUERY_OUTPUT_REGEX)?; - let mut output_str = self - .split_at(if multiline { - &EOF_REGEX - } else { - &DOUBLE_LINE_REGEX - })? - .trim_start(); + let mut output_str = self.split_at(if multiline { + &EOF_REGEX + } else { + &DOUBLE_LINE_REGEX + })?; + + // The `split_at(&QUERY_OUTPUT_REGEX)` stopped at the end of `----`, so `output_str` usually + // starts with a newline, which is not actually part of the expected output. Strip off this + // newline. + output_str = if let Some(output_str_stripped) = regexp_strip_prefix(output_str, &LINE_REGEX) + { + output_str_stripped + } else { + // There should always be a newline after `----`, because we have a lint that there is + // always a newline at the end of a file. However, we can still get here, when + // the expected output is empty, in which case the EOF_REGEX or DOUBLE_LINE_REGEX eats + // the newline at the end of the `----`. + assert!(output_str.is_empty()); + output_str + }; + // We don't want to advance the expected output past the column names so rewriting works, // but need to be able to parse past them, so remember the position before possible column // names. @@ -434,3 +448,16 @@ pub(crate) fn split_cols(line: &str, expected_columns: usize) -> Vec<&str> { line.split_whitespace().collect() } } + +pub fn regexp_strip_prefix<'a>(text: &'a str, regexp: &Regex) -> Option<&'a str> { + match regexp.find(text) { + Some(found) => { + if found.start() == 0 { + Some(&text[found.end()..]) + } else { + None + } + } + None => None, + } +} diff --git a/test/sqllogictest/mztimestamp.slt b/test/sqllogictest/mztimestamp.slt index 7ff759af3b8d9..fff765c77a8f4 100644 --- a/test/sqllogictest/mztimestamp.slt +++ b/test/sqllogictest/mztimestamp.slt @@ -78,7 +78,7 @@ SELECT 1::mz_catalog.mz_timestamp query T SELECT '1970-01-02'::date::mz_timestamp ---- - 86400000 +86400000 # Casts to timestamp[tz]. 8210266815600000 is roughly `HIGH_DATE` for `CheckedTimestamp`. query T diff --git a/test/sqllogictest/with_mutually_recursive.slt b/test/sqllogictest/with_mutually_recursive.slt index c03b37ac6d4b0..8a5bfbabc192e 100644 --- a/test/sqllogictest/with_mutually_recursive.slt +++ b/test/sqllogictest/with_mutually_recursive.slt @@ -669,3 +669,47 @@ query error db error: ERROR: WITH MUTUALLY RECURSIVE query "bar" declared types WITH MUTUALLY RECURSIVE bar(x list_numeric_scale_2) as (SELECT LIST['1'::TEXT]) SELECT x FROM bar + +## Adapted from https://www.sqlite.org/lang_with.html#outlandish_recursive_query_examples +query T multiline +WITH MUTUALLY RECURSIVE + xaxis(x double) AS (VALUES(-2.0) UNION ALL SELECT x+0.05 FROM xaxis WHERE x<1.2), + yaxis(y double) AS (VALUES(-1.0) UNION ALL SELECT y+0.1 FROM yaxis WHERE y<1.0), + m(iter int, cx double, cy double, x double, y double) AS ( + SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis + UNION ALL + SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m + WHERE (x*x + y*y) < 4.0 AND iter<28 + ), + m2(iter int, cx double, cy double) AS ( + SELECT max(iter), cx, cy FROM m GROUP BY cx, cy + ), + a(t text, cy double) AS ( + SELECT string_agg( substr(' .+*#', 1+least(iter/7,4), 1), '' ORDER BY cx), cy + FROM m2 GROUP BY cy + ) +SELECT string_agg(rtrim(t), chr(10) ORDER BY cy) FROM a; +---- + ....# + ..#*.. + ..+####+. + .......+####.... + + ..##+*##########+.++++ + .+.##################+. + .............+###################+.+ + ..++..#.....*#####################+. + ...+#######++#######################. + ....+*################################. + #############################################... + ....+*################################. + ...+#######++#######################. + ..++..#.....*#####################+. + .............+###################+.+ + .+.##################+. + ..##+*##########+.++++ + .......+####.... + + ..+####+. + ..#*.. + ....# + +. +EOF