This is an automated email from the ASF dual-hosted git repository.

ozankabak pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new c60b798cc0 Fix: Remove Unrelated Fields When Expanding Wildcards in 
Functional Dependency Projections (#12060)
c60b798cc0 is described below

commit c60b798cc0596c77127b728d6e8f08831c36ca1a
Author: Berkay Şahin <[email protected]>
AuthorDate: Mon Aug 19 18:49:01 2024 +0300

    Fix: Remove Unrelated Fields When Expanding Wildcards in Functional 
Dependency Projections (#12060)
    
    * Fix exprlist bug
    
    * Update datafusion/expr/src/utils.rs
    
    Co-authored-by: Mehmet Ozan Kabak <[email protected]>
    
    * Update utils.rs
    
    * Update joins.slt
    
    ---------
    
    Co-authored-by: Mehmet Ozan Kabak <[email protected]>
---
 datafusion/expr/src/utils.rs                 | 26 +++++++++++-
 datafusion/sqllogictest/test_files/joins.slt | 61 ++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/datafusion/expr/src/utils.rs b/datafusion/expr/src/utils.rs
index 4db5061e8f..5f5c468fa2 100644
--- a/datafusion/expr/src/utils.rs
+++ b/datafusion/expr/src/utils.rs
@@ -838,16 +838,38 @@ pub fn exprlist_len(
                 qualifier: Some(qualifier),
                 options,
             } => {
+                let related_wildcard_schema = 
wildcard_schema.as_ref().map_or_else(
+                    || Ok(Arc::clone(schema)),
+                    |schema| {
+                        // Eliminate the fields coming from other tables.
+                        let qualified_fields = schema
+                            .fields()
+                            .iter()
+                            .enumerate()
+                            .filter_map(|(idx, field)| {
+                                let (maybe_table_ref, _) = 
schema.qualified_field(idx);
+                                if maybe_table_ref.map_or(true, |q| q == 
qualifier) {
+                                    Some((maybe_table_ref.cloned(), 
Arc::clone(field)))
+                                } else {
+                                    None
+                                }
+                            })
+                            .collect::<Vec<_>>();
+                        let metadata = schema.metadata().clone();
+                        DFSchema::new_with_metadata(qualified_fields, metadata)
+                            .map(Arc::new)
+                    },
+                )?;
                 let excluded = get_excluded_columns(
                     options.exclude.as_ref(),
                     options.except.as_ref(),
-                    wildcard_schema.unwrap_or(schema),
+                    related_wildcard_schema.as_ref(),
                     Some(qualifier),
                 )?
                 .into_iter()
                 .collect::<HashSet<Column>>();
                 Ok(
-                    
get_exprs_except_skipped(wildcard_schema.unwrap_or(schema), excluded)
+                    get_exprs_except_skipped(related_wildcard_schema.as_ref(), 
excluded)
                         .len(),
                 )
             }
diff --git a/datafusion/sqllogictest/test_files/joins.slt 
b/datafusion/sqllogictest/test_files/joins.slt
index 9f036c3870..7af145fe3e 100644
--- a/datafusion/sqllogictest/test_files/joins.slt
+++ b/datafusion/sqllogictest/test_files/joins.slt
@@ -4044,3 +4044,64 @@ physical_plan
 03)----MemoryExec: partitions=1, partition_sizes=[1]
 04)----SortExec: TopK(fetch=10), expr=[b@1 ASC NULLS LAST], 
preserve_partitioning=[false]
 05)------MemoryExec: partitions=1, partition_sizes=[1]
+
+
+# Functional dependencies across a join
+statement ok
+CREATE TABLE sales_global (
+    ts TIMESTAMP,
+    sn INTEGER,
+    amount INTEGER,
+    currency VARCHAR NOT NULL,
+    primary key(sn)
+);
+
+statement ok
+CREATE TABLE exchange_rates (
+  ts TIMESTAMP,
+  sn INTEGER,
+  currency_from VARCHAR NOT NULL,
+  currency_to VARCHAR NOT NULL,
+  rate FLOAT,
+  primary key(sn)
+);
+
+query TT
+EXPLAIN SELECT s.*, s.amount * LAST_VALUE(e.rate) AS amount_usd
+FROM sales_global AS s
+JOIN exchange_rates AS e
+ON s.currency = e.currency_from AND
+   e.currency_to = 'USD' AND
+   s.ts >= e.ts
+GROUP BY s.sn
+ORDER BY s.sn
+----
+logical_plan
+01)Sort: s.sn ASC NULLS LAST
+02)--Projection: s.ts, s.sn, s.amount, s.currency, CAST(s.amount AS Float32) * 
last_value(e.rate) AS amount_usd
+03)----Aggregate: groupBy=[[s.sn, s.ts, s.amount, s.currency]], 
aggr=[[last_value(e.rate)]]
+04)------Projection: s.ts, s.sn, s.amount, s.currency, e.rate
+05)--------Inner Join: s.currency = e.currency_from Filter: s.ts >= e.ts
+06)----------SubqueryAlias: s
+07)------------TableScan: sales_global projection=[ts, sn, amount, currency]
+08)----------SubqueryAlias: e
+09)------------Projection: exchange_rates.ts, exchange_rates.currency_from, 
exchange_rates.rate
+10)--------------Filter: exchange_rates.currency_to = Utf8("USD")
+11)----------------TableScan: exchange_rates projection=[ts, currency_from, 
currency_to, rate]
+physical_plan
+01)SortExec: expr=[sn@1 ASC NULLS LAST], preserve_partitioning=[false]
+02)--ProjectionExec: expr=[ts@1 as ts, sn@0 as sn, amount@2 as amount, 
currency@3 as currency, CAST(amount@2 AS Float32) * last_value(e.rate)@4 as 
amount_usd]
+03)----AggregateExec: mode=Single, gby=[sn@1 as sn, ts@0 as ts, amount@2 as 
amount, currency@3 as currency], aggr=[last_value(e.rate)]
+04)------CoalesceBatchesExec: target_batch_size=3
+05)--------HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(currency@3, 
currency_from@1)], filter=ts@0 >= ts@1, projection=[ts@0, sn@1, amount@2, 
currency@3, rate@6]
+06)----------MemoryExec: partitions=1, partition_sizes=[0]
+07)----------ProjectionExec: expr=[ts@0 as ts, currency_from@1 as 
currency_from, rate@3 as rate]
+08)------------CoalesceBatchesExec: target_batch_size=3
+09)--------------FilterExec: currency_to@2 = USD
+10)----------------MemoryExec: partitions=1, partition_sizes=[0]
+
+statement ok
+DROP TABLE sales_global;
+
+statement ok
+DROP TABLE exchange_rates;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to