You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Based on the conversations in the prior PRs and issues it looks like there was consensus that this feature should live in datafusion as opposed to arrow, so creating an issue here.
Describe the solution you'd like
A built-in function supported for both SQL and DataFrame APIs input_file_name() that returns a string of the file from which the row was originally scanned.
I am interested in implementing this as requested by discussion#7979, just checked the the previous PRs, and here are my thoughts:
What is the correct semantics of this input_file_name() function
Return all the files registered by a table ~~
The file that a specific row comes from (at runtime/execution time)
arrow#9944 seems to choose option 1 if I understand correctly, in my use case, I would like to have option 2.
Update: after taking a detailed look at that PR, I realized it implemented the option 2 by storing the filename in the Schema.metadata
For option 1, this info is stored in different file's ExecutionPlan node, we can fetch it after generating the physical plan
For option 2, this info will be available when different file's XXXOpener type actually opens a file (whether on the local file system or object storage)
Friendly ping @alamb and @jorgecarleitao since you guys were the reviewer of the previous PR, I would like to hear your thoughts! :)
And, haven't made any serious contributions to DataFusion, guidance would be hightly appreciated!
What is the correct semantics of this input_file_name() function
I do not know. However, the use case of " that returns a string of the file from which the row was originally scanned" suggests it would be i in your list: "Return all the files registered by a table"
Creates a string column for the file name of the current Spark task.
I am not sure how that maps to what file is processed (aka does the same task process multiple input files?)
As for implementation, perhaps it would be possible to model how partition columns are injected, though as you will find that is non trivial to implement.
maybe we can implement option ii (The file that a specific row comes from) by use an extension type marker and fill it in via FIleScanConfig or ParquetOpener, similar to what arrow-rs does at the row group level in apache/arrow-rs#9117
Reacted by Andrew Lamb, Matthew Kim and Malthe Karbo
I also think the ListingTableProvider is in signficantly better shape now. If we could model the file name as a "partition column" it may nicely just work
+1 - This is the “file identity” half we need for file aware table format semantics.
We hit an issue in delta-rs where DF coalesced batches across file boundaries (fixed in next-scan), which surfaced that relying on implicit stream ordering is fragile for DV semantics and log replay. delta-io/delta-rs#4115.
input_file_name() can get us to a stable (file, …) key. For fully order insensitive DV reads/writes we would also need (…, row_position) (0-based file ordinal)See #13261.
This would be a big help for us on the delta-rs side. Happy to take this on or help however needed. Lmk what would be most useful.
@ethan-tyler it would be great if you wanted to work on this
I would suggest: Sketching out a PR to get the feature to work (basically a plumbing exercise) and then we can figure out how to break it down into smaller PRs for review
I would personally recommend starting with a slt test that shows what you want to do -- like
CREATE EXTERNAL TABLE t AS ...
-- not sure what the syntax would be hereSELECT col1, __filename from t
May I suggest that since scans can now receive expressions we make a function called filename() that is implemented to return null by default but that scans swap out with the literal filename if they see it in the projection?
Could be implemented as a “trivial expression” that we’ve been discussing Andrew. But there might also be too many implementation challenges getting it down into the scan.
A function that gets pushed down (and rewritten by the file opener (which knows the file name)) sounds like a great idea to me
As you know… the issue will be making sure it’s always pushed down. select min(col), max(col) from t group by filename() order by filename() should ideally work.
@alamb - Awesome! Happy to take this on, appreciate the endorsement!
Starting with an SLT for Parquet external tables:
CREATE EXTERNAL TABLE t STORED AS PARQUET LOCATION '...';
SELECT col1, input_file_name() FROM t;
I’d prefer keeping the semantics “Spark-like” with input_file_name() , can adjust if we prefer filename().
@adriangb - Love it :) Trivial expression that defaults to NULL, rewritten by file opener. Cost paid only when referenced and no schema mutation. Composes well with (file, row_position) direction for DV semantics (#13261).
Good point on ensuring pushdown for GROUP BY filename() / ORDER BY filename(). May need the rewrite early in planning so downstream operators see the resolved column. I'll reach out if that gets tricky.
I'll prototype the rewrite in Parquet scan first (per-row literal, likely dictionary encoded). Once SLT passes, I'll open a draft PR to iterate on naming/semantics and gather feedback before splitting into reviewable pieces.
Good point on ensuring pushdown for GROUP BY filename() / ORDER BY filename(). May need the rewrite early in planning so downstream operators see the resolved column. I'll reach out if that gets tricky.
Oh it will! Andrew and I are working on exactly this problem but for struct field access. I’d say let’s not duplicate effort in this regard. So maybe like you say start with “what if this expression is in a projection right above the ParquetSource” and then we can work on making sure it gets there from the GroupBy. Some background: #19538. I need to do work on this PR but maybe I can also tag you for review on related work?
@adriangb - Perfect, happy to start with the projection above ParquetSource case and let the broader pushdown work land separately. Will check out #19538 for context.
A function that gets pushed down (and rewritten by the file opener (which knows the file name)) sounds like a great idea to me
As you know… the issue will be making sure it’s always pushed down. select min(col), max(col) from t group by filename() order by filename() should ideally work.
From my perspective, I actually think it would be ok if we started with input_file_name() that only worked in select lists at first (aka only worked when it could be pushed down) and then we expanded the support over time
Reacted by Ethan Urbanski and Adrian Garcia Badaracco
Activity
SteveLauC commentedon Nov 3, 2023
I am interested in implementing this as requested by discussion#7979, just checked the the previous PRs, and here are my thoughts:
What is the correct semantics of this
input_file_name()functionFor option 1, this info is stored in different file's
ExecutionPlannode, we can fetch it after generating the physical planFor option 2, this info will be available when different file's
XXXOpenertype actually opens a file (whether on the local file system or object storage)Friendly ping @alamb and @jorgecarleitao since you guys were the reviewer of the previous PR, I would like to hear your thoughts! :)
And, haven't made any serious contributions to DataFusion, guidance would be hightly appreciated!
alamb commentedon Nov 3, 2023
I do not know. However, the use case of " that returns a string of the file from which the row was originally scanned" suggests it would be
iin your list: "Return all the files registered by a table"The spark docs say
I am not sure how that maps to what file is processed (aka does the same task process multiple input files?)
As for implementation, perhaps it would be possible to model how partition columns are injected, though as you will find that is non trivial to implement.
alamb commentedon Nov 3, 2023
My "gut feeling" is that this will be a very complicated feature to implement with the existing Listing table provider.
adriangb commentedon Jan 14, 2026
copying #18494 (comment) over here:
maybe we can implement option
ii(The file that a specific row comes from) by use an extension type marker and fill it in viaFIleScanConfigorParquetOpener, similar to what arrow-rs does at the row group level in apache/arrow-rs#9117alamb commentedon Jan 14, 2026
I also think the ListingTableProvider is in signficantly better shape now. If we could model the file name as a "partition column" it may nicely just work
ethan-tyler commentedon Jan 23, 2026
+1 - This is the “file identity” half we need for file aware table format semantics.
We hit an issue in delta-rs where DF coalesced batches across file boundaries (fixed in next-scan), which surfaced that relying on implicit stream ordering is fragile for DV semantics and log replay. delta-io/delta-rs#4115.
input_file_name()can get us to a stable(file, …)key. For fully order insensitive DV reads/writes we would also need(…, row_position)(0-based file ordinal)See #13261.This would be a big help for us on the delta-rs side. Happy to take this on or help however needed. Lmk what would be most useful.
alamb commentedon Jan 23, 2026
@ethan-tyler it would be great if you wanted to work on this
I would suggest: Sketching out a PR to get the feature to work (basically a plumbing exercise) and then we can figure out how to break it down into smaller PRs for review
I would personally recommend starting with a
slttest that shows what you want to do -- likeadriangb commentedon Jan 23, 2026
May I suggest that since scans can now receive expressions we make a function called
filename()that is implemented to return null by default but that scans swap out with the literal filename if they see it in the projection?Could be implemented as a “trivial expression” that we’ve been discussing Andrew. But there might also be too many implementation challenges getting it down into the scan.
alamb commentedon Jan 23, 2026
A function that gets pushed down (and rewritten by the file opener (which knows the file name)) sounds like a great idea to me
adriangb commentedon Jan 23, 2026
As you know… the issue will be making sure it’s always pushed down.
select min(col), max(col) from t group by filename() order by filename()should ideally work.ethan-tyler commentedon Jan 23, 2026
@alamb - Awesome! Happy to take this on, appreciate the endorsement!
Starting with an SLT for Parquet external tables:
I’d prefer keeping the semantics “Spark-like” with
input_file_name(), can adjust if we preferfilename().@adriangb - Love it :) Trivial expression that defaults to NULL, rewritten by file opener. Cost paid only when referenced and no schema mutation. Composes well with
(file, row_position)direction for DV semantics (#13261).Good point on ensuring pushdown for
GROUP BY filename()/ORDER BY filename(). May need the rewrite early in planning so downstream operators see the resolved column. I'll reach out if that gets tricky.I'll prototype the rewrite in Parquet scan first (per-row literal, likely dictionary encoded). Once SLT passes, I'll open a draft PR to iterate on naming/semantics and gather feedback before splitting into reviewable pieces.
adriangb commentedon Jan 23, 2026
Oh it will! Andrew and I are working on exactly this problem but for struct field access. I’d say let’s not duplicate effort in this regard. So maybe like you say start with “what if this expression is in a projection right above the ParquetSource” and then we can work on making sure it gets there from the GroupBy. Some background: #19538. I need to do work on this PR but maybe I can also tag you for review on related work?
ethan-tyler commentedon Jan 23, 2026
@adriangb - Perfect, happy to start with the projection above ParquetSource case and let the broader pushdown work land separately. Will check out #19538 for context.
You can always tag me on reviews, happy to help!
alamb commentedon Jan 24, 2026
From my perspective, I actually think it would be ok if we started with
input_file_name()that only worked in select lists at first (aka only worked when it could be pushed down) and then we expanded the support over timealamb commentedon Feb 3, 2026
I made an epic to track metadata discussions
alamb commentedon Feb 3, 2026
See discussion #20135 (comment)
Using a function approach may make it tricky to do multi-table queries
AdamGS commentedon Jun 15, 2026
take
AdamGS commentedon Jun 15, 2026
taking over from @ethan-tyler
feat: Add new `input_file_name` UDF for file-backed scans (apache#22978)