@@ -2056,7 +2056,7 @@ fn expand_cte_queries(sql: &str) -> CteExpansion {
20562056 }
20572057}
20582058
2059- fn top_level_parenthesized_query_body ( sql : & str ) -> Option < & str > {
2059+ fn top_level_parenthesized_query_body_range ( sql : & str ) -> Option < ( usize , usize ) > {
20602060 let upper = sql. to_uppercase ( ) ;
20612061 let mut idx = 0 ;
20622062 while let Some ( as_pos) = find_top_level_keyword ( sql, "AS" , idx) {
@@ -2067,7 +2067,8 @@ fn top_level_parenthesized_query_body(sql: &str) -> Option<&str> {
20672067 || matches_keyword_at ( & upper, body_start, "WITH" )
20682068 {
20692069 if let Ok ( ( _, body) ) = balanced_parens ( & sql[ open_pos + 1 ..] ) {
2070- return Some ( body) ;
2070+ let start = open_pos + 1 ;
2071+ return Some ( ( start, start + body. len ( ) ) ) ;
20712072 }
20722073 }
20732074 }
@@ -2076,6 +2077,10 @@ fn top_level_parenthesized_query_body(sql: &str) -> Option<&str> {
20762077 None
20772078}
20782079
2080+ fn top_level_parenthesized_query_body ( sql : & str ) -> Option < & str > {
2081+ top_level_parenthesized_query_body_range ( sql) . map ( |( start, end) | & sql[ start..end] )
2082+ }
2083+
20792084fn extract_base_relation_sql ( view_query : & str ) -> Option < String > {
20802085 let query = view_query. trim ( ) . trim_end_matches ( ';' ) . trim ( ) ;
20812086 if query. is_empty ( ) {
@@ -5955,6 +5960,26 @@ fn dimension_key_in_group_by(ident: &str, group_by_cols: &[String]) -> bool {
59555960 } )
59565961}
59575962
5963+ fn effective_at_where_filter_identifiers ( modifiers : & [ ContextModifier ] ) -> Vec < String > {
5964+ if modifiers
5965+ . iter ( )
5966+ . any ( |modifier| matches ! ( modifier, ContextModifier :: AllGlobal ) )
5967+ {
5968+ return Vec :: new ( ) ;
5969+ }
5970+
5971+ modifiers
5972+ . iter ( )
5973+ . find_map ( |modifier| {
5974+ if let ContextModifier :: Where ( condition) = modifier {
5975+ Some ( extract_where_filter_identifiers ( condition) )
5976+ } else {
5977+ None
5978+ }
5979+ } )
5980+ . unwrap_or_default ( )
5981+ }
5982+
59585983fn warning_for_at_all_ungrouped_where (
59595984 measure_name : & str ,
59605985 modifiers : & [ ContextModifier ] ,
@@ -6001,19 +6026,7 @@ fn warning_for_at_all_ungrouped_where(
60016026 . iter ( )
60026027 . enumerate ( )
60036028 . filter_map ( |( idx, modifier) | {
6004- if let ContextModifier :: Where ( condition) = modifier {
6005- let cleared_by_global_all = modifiers
6006- . iter ( )
6007- . enumerate ( )
6008- . any ( |( all_idx, other) | {
6009- all_idx != idx && matches ! ( other, ContextModifier :: AllGlobal )
6010- } ) ;
6011- if cleared_by_global_all {
6012- None
6013- } else {
6014- Some ( extract_where_filter_identifiers ( condition) )
6015- }
6016- } else if let ContextModifier :: Set ( dim, _) = modifier {
6029+ if let ContextModifier :: Set ( dim, _) = modifier {
60176030 let dim_key = normalize_dimension_key ( dim. split ( '.' ) . next_back ( ) . unwrap_or ( dim) . trim ( ) ) ;
60186031 let removed_by_all =
60196032 modifiers. iter ( ) . enumerate ( ) . any ( |( all_idx, other) | {
@@ -6041,6 +6054,10 @@ fn warning_for_at_all_ungrouped_where(
60416054 } )
60426055 . flatten ( )
60436056 . collect ( ) ;
6057+ let encoded_filter_dims: HashSet < String > = encoded_filter_dims
6058+ . into_iter ( )
6059+ . chain ( effective_at_where_filter_identifiers ( modifiers) )
6060+ . collect ( ) ;
60446061 let mut ungrouped_filters: Vec < String > = extract_where_filter_identifiers ( where_clause)
60456062 . into_iter ( )
60466063 . filter ( |ident| source_dims. is_empty ( ) || source_dims. contains ( ident) )
@@ -6067,7 +6084,30 @@ fn warning_for_at_all_ungrouped_where(
60676084
60686085/// Expand AGGREGATE() with AT modifiers in SQL
60696086pub fn expand_aggregate_with_at ( sql : & str ) -> AggregateExpandResult {
6070- let cte_expansion = expand_cte_queries ( sql) ;
6087+ let cte_expansion = if let Some ( ( body_start, body_end) ) =
6088+ top_level_parenthesized_query_body_range ( sql)
6089+ {
6090+ let body_sql = & sql[ body_start..body_end] ;
6091+ let body_expansion = expand_cte_queries ( body_sql) ;
6092+ if body_expansion. had_aggregate
6093+ || body_expansion. sql != body_sql
6094+ || !body_expansion. warnings . is_empty ( )
6095+ {
6096+ let mut expanded_sql = sql. to_string ( ) ;
6097+ if body_expansion. sql != body_sql {
6098+ expanded_sql. replace_range ( body_start..body_end, & body_expansion. sql ) ;
6099+ }
6100+ CteExpansion {
6101+ sql : expanded_sql,
6102+ had_aggregate : body_expansion. had_aggregate ,
6103+ warnings : body_expansion. warnings ,
6104+ }
6105+ } else {
6106+ expand_cte_queries ( sql)
6107+ }
6108+ } else {
6109+ expand_cte_queries ( sql)
6110+ } ;
60716111 let mut sql = cte_expansion. sql ;
60726112 let mut had_aggregate = cte_expansion. had_aggregate ;
60736113 let mut warnings = cte_expansion. warnings ;
@@ -7520,6 +7560,49 @@ FROM orders"#;
75207560 assert ! ( warning. is_none( ) ) ;
75217561 }
75227562
7563+ #[ test]
7564+ fn test_at_all_warns_when_filter_only_in_overwritten_at_where ( ) {
7565+ let source_dims = HashSet :: from ( [
7566+ normalize_identifier_name ( "year" ) ,
7567+ normalize_identifier_name ( "region" ) ,
7568+ normalize_identifier_name ( "category" ) ,
7569+ ] ) ;
7570+ let warning = warning_for_at_all_ungrouped_where (
7571+ "revenue" ,
7572+ & [
7573+ ContextModifier :: All ( "region" . to_string ( ) ) ,
7574+ ContextModifier :: Where ( "category = 'A'" . to_string ( ) ) ,
7575+ ContextModifier :: Where ( "year = 2024" . to_string ( ) ) ,
7576+ ] ,
7577+ Some ( "year = 2024" ) ,
7578+ & [ "region" . to_string ( ) ] ,
7579+ & source_dims,
7580+ )
7581+ . unwrap ( ) ;
7582+ assert ! ( warning. contains( "year" ) ) ;
7583+ }
7584+
7585+ #[ test]
7586+ fn test_at_all_does_not_warn_when_filter_in_effective_at_where ( ) {
7587+ let source_dims = HashSet :: from ( [
7588+ normalize_identifier_name ( "year" ) ,
7589+ normalize_identifier_name ( "region" ) ,
7590+ normalize_identifier_name ( "category" ) ,
7591+ ] ) ;
7592+ let warning = warning_for_at_all_ungrouped_where (
7593+ "revenue" ,
7594+ & [
7595+ ContextModifier :: All ( "region" . to_string ( ) ) ,
7596+ ContextModifier :: Where ( "year = 2024" . to_string ( ) ) ,
7597+ ContextModifier :: Where ( "category = 'A'" . to_string ( ) ) ,
7598+ ] ,
7599+ Some ( "year = 2024" ) ,
7600+ & [ "region" . to_string ( ) ] ,
7601+ & source_dims,
7602+ ) ;
7603+ assert ! ( warning. is_none( ) ) ;
7604+ }
7605+
75237606 #[ test]
75247607 fn test_at_all_does_not_warn_when_set_encodes_filter_dimension ( ) {
75257608 let source_dims = HashSet :: from ( [
0 commit comments