@@ -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 ( ) {
@@ -5767,6 +5772,26 @@ fn dimension_key_in_group_by(ident: &str, group_by_cols: &[String]) -> bool {
57675772 } )
57685773}
57695774
5775+ fn effective_at_where_filter_identifiers ( modifiers : & [ ContextModifier ] ) -> Vec < String > {
5776+ if modifiers
5777+ . iter ( )
5778+ . any ( |modifier| matches ! ( modifier, ContextModifier :: AllGlobal ) )
5779+ {
5780+ return Vec :: new ( ) ;
5781+ }
5782+
5783+ modifiers
5784+ . iter ( )
5785+ . find_map ( |modifier| {
5786+ if let ContextModifier :: Where ( condition) = modifier {
5787+ Some ( extract_where_filter_identifiers ( condition) )
5788+ } else {
5789+ None
5790+ }
5791+ } )
5792+ . unwrap_or_default ( )
5793+ }
5794+
57705795fn warning_for_at_all_ungrouped_where (
57715796 measure_name : & str ,
57725797 modifiers : & [ ContextModifier ] ,
@@ -5813,19 +5838,7 @@ fn warning_for_at_all_ungrouped_where(
58135838 . iter ( )
58145839 . enumerate ( )
58155840 . filter_map ( |( idx, modifier) | {
5816- if let ContextModifier :: Where ( condition) = modifier {
5817- let cleared_by_global_all = modifiers
5818- . iter ( )
5819- . enumerate ( )
5820- . any ( |( all_idx, other) | {
5821- all_idx != idx && matches ! ( other, ContextModifier :: AllGlobal )
5822- } ) ;
5823- if cleared_by_global_all {
5824- None
5825- } else {
5826- Some ( extract_where_filter_identifiers ( condition) )
5827- }
5828- } else if let ContextModifier :: Set ( dim, _) = modifier {
5841+ if let ContextModifier :: Set ( dim, _) = modifier {
58295842 let dim_key = normalize_dimension_key ( dim. split ( '.' ) . next_back ( ) . unwrap_or ( dim) . trim ( ) ) ;
58305843 let removed_by_all =
58315844 modifiers. iter ( ) . enumerate ( ) . any ( |( all_idx, other) | {
@@ -5853,6 +5866,10 @@ fn warning_for_at_all_ungrouped_where(
58535866 } )
58545867 . flatten ( )
58555868 . collect ( ) ;
5869+ let encoded_filter_dims: HashSet < String > = encoded_filter_dims
5870+ . into_iter ( )
5871+ . chain ( effective_at_where_filter_identifiers ( modifiers) )
5872+ . collect ( ) ;
58565873 let mut ungrouped_filters: Vec < String > = extract_where_filter_identifiers ( where_clause)
58575874 . into_iter ( )
58585875 . filter ( |ident| source_dims. is_empty ( ) || source_dims. contains ( ident) )
@@ -5879,7 +5896,30 @@ fn warning_for_at_all_ungrouped_where(
58795896
58805897/// Expand AGGREGATE() with AT modifiers in SQL
58815898pub fn expand_aggregate_with_at ( sql : & str ) -> AggregateExpandResult {
5882- let cte_expansion = expand_cte_queries ( sql) ;
5899+ let cte_expansion = if let Some ( ( body_start, body_end) ) =
5900+ top_level_parenthesized_query_body_range ( sql)
5901+ {
5902+ let body_sql = & sql[ body_start..body_end] ;
5903+ let body_expansion = expand_cte_queries ( body_sql) ;
5904+ if body_expansion. had_aggregate
5905+ || body_expansion. sql != body_sql
5906+ || !body_expansion. warnings . is_empty ( )
5907+ {
5908+ let mut expanded_sql = sql. to_string ( ) ;
5909+ if body_expansion. sql != body_sql {
5910+ expanded_sql. replace_range ( body_start..body_end, & body_expansion. sql ) ;
5911+ }
5912+ CteExpansion {
5913+ sql : expanded_sql,
5914+ had_aggregate : body_expansion. had_aggregate ,
5915+ warnings : body_expansion. warnings ,
5916+ }
5917+ } else {
5918+ expand_cte_queries ( sql)
5919+ }
5920+ } else {
5921+ expand_cte_queries ( sql)
5922+ } ;
58835923 let mut sql = cte_expansion. sql ;
58845924 let mut had_aggregate = cte_expansion. had_aggregate ;
58855925 let mut warnings = cte_expansion. warnings ;
@@ -7218,6 +7258,49 @@ FROM orders"#;
72187258 assert ! ( warning. is_none( ) ) ;
72197259 }
72207260
7261+ #[ test]
7262+ fn test_at_all_warns_when_filter_only_in_overwritten_at_where ( ) {
7263+ let source_dims = HashSet :: from ( [
7264+ normalize_identifier_name ( "year" ) ,
7265+ normalize_identifier_name ( "region" ) ,
7266+ normalize_identifier_name ( "category" ) ,
7267+ ] ) ;
7268+ let warning = warning_for_at_all_ungrouped_where (
7269+ "revenue" ,
7270+ & [
7271+ ContextModifier :: All ( "region" . to_string ( ) ) ,
7272+ ContextModifier :: Where ( "category = 'A'" . to_string ( ) ) ,
7273+ ContextModifier :: Where ( "year = 2024" . to_string ( ) ) ,
7274+ ] ,
7275+ Some ( "year = 2024" ) ,
7276+ & [ "region" . to_string ( ) ] ,
7277+ & source_dims,
7278+ )
7279+ . unwrap ( ) ;
7280+ assert ! ( warning. contains( "year" ) ) ;
7281+ }
7282+
7283+ #[ test]
7284+ fn test_at_all_does_not_warn_when_filter_in_effective_at_where ( ) {
7285+ let source_dims = HashSet :: from ( [
7286+ normalize_identifier_name ( "year" ) ,
7287+ normalize_identifier_name ( "region" ) ,
7288+ normalize_identifier_name ( "category" ) ,
7289+ ] ) ;
7290+ let warning = warning_for_at_all_ungrouped_where (
7291+ "revenue" ,
7292+ & [
7293+ ContextModifier :: All ( "region" . to_string ( ) ) ,
7294+ ContextModifier :: Where ( "year = 2024" . to_string ( ) ) ,
7295+ ContextModifier :: Where ( "category = 'A'" . to_string ( ) ) ,
7296+ ] ,
7297+ Some ( "year = 2024" ) ,
7298+ & [ "region" . to_string ( ) ] ,
7299+ & source_dims,
7300+ ) ;
7301+ assert ! ( warning. is_none( ) ) ;
7302+ }
7303+
72217304 #[ test]
72227305 fn test_at_all_does_not_warn_when_set_encodes_filter_dimension ( ) {
72237306 let source_dims = HashSet :: from ( [
0 commit comments