@@ -171,6 +171,37 @@ pub trait TableProvider: Debug + Sync + Send {
171171 limit : Option < usize > ,
172172 ) -> Result < Arc < dyn ExecutionPlan > > ;
173173
174+ /// Create an [`ExecutionPlan`] for scanning the table using structured arguments.
175+ ///
176+ /// This method uses [`ScanArgs`] to pass scan parameters in a structured way
177+ /// and returns a [`ScanResult`] containing the execution plan.
178+ ///
179+ /// Table providers can override this method to take advantage of additional
180+ /// parameters like the upcoming `preferred_ordering` that may not be available through
181+ /// other scan methods.
182+ ///
183+ /// # Arguments
184+ /// * `state` - The session state containing configuration and context
185+ /// * `args` - Structured scan arguments including projection, filters, limit, and ordering preferences
186+ ///
187+ /// # Returns
188+ /// A [`ScanResult`] containing the [`ExecutionPlan`] for scanning the table
189+ ///
190+ /// See [`Self::scan`] for detailed documentation about projection, filters, and limits.
191+ async fn scan_with_args < ' a > (
192+ & self ,
193+ state : & dyn Session ,
194+ args : ScanArgs < ' a > ,
195+ ) -> Result < ScanResult > {
196+ let filters = args. filters ( ) . unwrap_or ( & [ ] ) ;
197+ let projection = args. projection ( ) . map ( |p| p. to_vec ( ) ) ;
198+ let limit = args. limit ( ) ;
199+ let plan = self
200+ . scan ( state, projection. as_ref ( ) , filters, limit)
201+ . await ?;
202+ Ok ( plan. into ( ) )
203+ }
204+
174205 /// Specify if DataFusion should provide filter expressions to the
175206 /// TableProvider to apply *during* the scan.
176207 ///
@@ -299,6 +330,114 @@ pub trait TableProvider: Debug + Sync + Send {
299330 }
300331}
301332
333+ /// Arguments for scanning a table with [`TableProvider::scan_with_args`].
334+ #[ derive( Debug , Clone , Default ) ]
335+ pub struct ScanArgs < ' a > {
336+ filters : Option < & ' a [ Expr ] > ,
337+ projection : Option < & ' a [ usize ] > ,
338+ limit : Option < usize > ,
339+ }
340+
341+ impl < ' a > ScanArgs < ' a > {
342+ /// Set the column projection for the scan.
343+ ///
344+ /// The projection is a list of column indices from [`TableProvider::schema`]
345+ /// that should be included in the scan results. If `None`, all columns are included.
346+ ///
347+ /// # Arguments
348+ /// * `projection` - Optional slice of column indices to project
349+ pub fn with_projection ( mut self , projection : Option < & ' a [ usize ] > ) -> Self {
350+ self . projection = projection;
351+ self
352+ }
353+
354+ /// Get the column projection for the scan.
355+ ///
356+ /// Returns a reference to the projection column indices, or `None` if
357+ /// no projection was specified (meaning all columns should be included).
358+ pub fn projection ( & self ) -> Option < & ' a [ usize ] > {
359+ self . projection
360+ }
361+
362+ /// Set the filter expressions for the scan.
363+ ///
364+ /// Filters are boolean expressions that should be evaluated during the scan
365+ /// to reduce the number of rows returned. All expressions are combined with AND logic.
366+ /// Whether filters are actually pushed down depends on [`TableProvider::supports_filters_pushdown`].
367+ ///
368+ /// # Arguments
369+ /// * `filters` - Optional slice of filter expressions
370+ pub fn with_filters ( mut self , filters : Option < & ' a [ Expr ] > ) -> Self {
371+ self . filters = filters;
372+ self
373+ }
374+
375+ /// Get the filter expressions for the scan.
376+ ///
377+ /// Returns a reference to the filter expressions, or `None` if no filters were specified.
378+ pub fn filters ( & self ) -> Option < & ' a [ Expr ] > {
379+ self . filters
380+ }
381+
382+ /// Set the maximum number of rows to return from the scan.
383+ ///
384+ /// If specified, the scan should return at most this many rows. This is typically
385+ /// used to optimize queries with `LIMIT` clauses.
386+ ///
387+ /// # Arguments
388+ /// * `limit` - Optional maximum number of rows to return
389+ pub fn with_limit ( mut self , limit : Option < usize > ) -> Self {
390+ self . limit = limit;
391+ self
392+ }
393+
394+ /// Get the maximum number of rows to return from the scan.
395+ ///
396+ /// Returns the row limit, or `None` if no limit was specified.
397+ pub fn limit ( & self ) -> Option < usize > {
398+ self . limit
399+ }
400+ }
401+
402+ /// Result of a table scan operation from [`TableProvider::scan_with_args`].
403+ #[ derive( Debug , Clone ) ]
404+ pub struct ScanResult {
405+ /// The ExecutionPlan to run.
406+ plan : Arc < dyn ExecutionPlan > ,
407+ }
408+
409+ impl ScanResult {
410+ /// Create a new `ScanResult` with the given execution plan.
411+ ///
412+ /// # Arguments
413+ /// * `plan` - The execution plan that will perform the table scan
414+ pub fn new ( plan : Arc < dyn ExecutionPlan > ) -> Self {
415+ Self { plan }
416+ }
417+
418+ /// Get a reference to the execution plan for this scan result.
419+ ///
420+ /// Returns a reference to the [`ExecutionPlan`] that will perform
421+ /// the actual table scanning and data retrieval.
422+ pub fn plan ( & self ) -> & Arc < dyn ExecutionPlan > {
423+ & self . plan
424+ }
425+
426+ /// Consume this ScanResult and return the execution plan.
427+ ///
428+ /// Returns the owned [`ExecutionPlan`] that will perform
429+ /// the actual table scanning and data retrieval.
430+ pub fn into_inner ( self ) -> Arc < dyn ExecutionPlan > {
431+ self . plan
432+ }
433+ }
434+
435+ impl From < Arc < dyn ExecutionPlan > > for ScanResult {
436+ fn from ( plan : Arc < dyn ExecutionPlan > ) -> Self {
437+ Self :: new ( plan)
438+ }
439+ }
440+
302441/// A factory which creates [`TableProvider`]s at runtime given a URL.
303442///
304443/// For example, this can be used to create a table "on the fly"
0 commit comments