mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-07-08 06:50:39 +00:00
fix(flow): support complex SQL full-query flows (#8242)
* fix(flow): skip TWE detection for complex plans Signed-off-by: discord9 <discord9@163.com> * chore: helper Signed-off-by: discord9 <discord9@163.com> * fix(flow): allow SQL CTE flow parsing Signed-off-by: discord9 <discord9@163.com> * fix(flow): execute unscoped SQL snapshots as SQL Signed-off-by: discord9 <discord9@163.com> * fix: column list Signed-off-by: discord9 <discord9@163.com> * refactor: per review Signed-off-by: discord9 <discord9@163.com> --------- Signed-off-by: discord9 <discord9@163.com>
This commit is contained in:
@@ -410,7 +410,7 @@ impl<'a> ParserContext<'a> {
|
||||
.fail();
|
||||
};
|
||||
|
||||
if !utils::is_simple_tql_cte_query(query) {
|
||||
if utils::has_tql_cte(query) && !utils::is_simple_tql_cte_query(query) {
|
||||
return InvalidFlowQuerySnafu {
|
||||
reason: "WITH is only supported for the simplest TQL CTE in CREATE FLOW"
|
||||
.to_string(),
|
||||
@@ -1962,7 +1962,7 @@ SELECT * FROM tql;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_create_flow_with_sql_cte_is_unsupported() {
|
||||
fn test_parse_create_flow_with_sql_cte_is_supported() {
|
||||
let sql = r#"
|
||||
CREATE FLOW f
|
||||
SINK TO s
|
||||
@@ -1970,11 +1970,17 @@ AS
|
||||
WITH cte AS (SELECT 1) SELECT * FROM cte;
|
||||
"#;
|
||||
|
||||
let err =
|
||||
let stmts =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap_err();
|
||||
let msg = err.to_string();
|
||||
assert!(msg.to_uppercase().contains("WITH"), "err: {msg}");
|
||||
.unwrap();
|
||||
assert_eq!(1, stmts.len());
|
||||
let Statement::CreateFlow(create_flow) = &stmts[0] else {
|
||||
panic!("unexpected stmt: {:?}", stmts[0]);
|
||||
};
|
||||
assert_eq!(
|
||||
"WITH cte AS (SELECT 1) SELECT * FROM cte",
|
||||
create_flow.query.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -98,6 +98,14 @@ pub(crate) fn is_simple_tql_cte_query(query: &Query) -> bool {
|
||||
reference == cte_name
|
||||
}
|
||||
|
||||
pub(crate) fn has_tql_cte(query: &Query) -> bool {
|
||||
query.hybrid_cte.as_ref().is_some_and(|with| {
|
||||
with.cte_tables
|
||||
.iter()
|
||||
.any(|cte| matches!(cte.content, CteContent::Tql(_)))
|
||||
})
|
||||
}
|
||||
|
||||
fn has_only_hybrid_tql_cte(query: &Query) -> bool {
|
||||
query
|
||||
.inner
|
||||
|
||||
@@ -146,15 +146,14 @@ impl ParserContext<'_> {
|
||||
// Parse the main query
|
||||
let main_query = self.parser.parse_query().context(error::SyntaxSnafu)?;
|
||||
|
||||
// Convert the hybrid CTEs to a standard query with hybrid metadata
|
||||
let hybrid_cte = HybridCteWith {
|
||||
recursive,
|
||||
cte_tables: tql_cte_tables,
|
||||
};
|
||||
|
||||
// Create a Query statement with hybrid CTE metadata
|
||||
let mut query = Query::try_from(*main_query)?;
|
||||
query.hybrid_cte = Some(hybrid_cte);
|
||||
if !tql_cte_tables.is_empty() {
|
||||
query.hybrid_cte = Some(HybridCteWith {
|
||||
recursive,
|
||||
cte_tables: tql_cte_tables,
|
||||
});
|
||||
}
|
||||
query.inner.with = Some(With {
|
||||
recursive,
|
||||
cte_tables: sql_cte_tables,
|
||||
|
||||
@@ -108,5 +108,11 @@ mod test {
|
||||
.to_string(),
|
||||
"WITH tql_cte AS (TQL EVAL (0, 100, '5s') up) SELECT * FROM tql_cte"
|
||||
);
|
||||
assert_eq!(
|
||||
create_query("WITH sql_cte AS (SELECT 1) SELECT * FROM sql_cte")
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
"WITH sql_cte AS (SELECT 1) SELECT * FROM sql_cte"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user