@@ -87,7 +87,7 @@ pub trait TableProvider: Debug + Sync + Send {
8787 /// Create an [`ExecutionPlan`] for scanning the table with optionally
8888 /// specified `projection`, `filter` and `limit`, described below.
8989 ///
90- /// The `ExecutionPlan` is responsible scanning the datasource's
90+ /// The returned `ExecutionPlan` is responsible scanning the datasource's
9191 /// partitions in a streaming, parallelized fashion.
9292 ///
9393 /// # Projection
@@ -163,6 +163,29 @@ pub trait TableProvider: Debug + Sync + Send {
163163 /// because inexact filters do not guarantee that every filtered row is
164164 /// removed, so applying the limit could lead to too few rows being available
165165 /// to return as a final result.
166+ ///
167+ /// ## Evaluation Order
168+ ///
169+ /// The logical evaluation is first `filters` then `limit` and then `projection`.
170+ ///
171+ /// Note that `limit` applies to the filtered result, not to the unfiltered
172+ /// input, and `projection` affects only which columns are returned, not
173+ /// which rows qualify.
174+ ///
175+ /// For example, if a scan receives:
176+ ///
177+ /// - `projection = [a]`
178+ /// - `filters = [b > 5]`
179+ /// - `limit = Some(3)`
180+ ///
181+ /// It logically must produce results like:
182+ ///
183+ /// ```text
184+ /// PROJECTION a (LIMIT 3 (SCAN WHERE b > 5))
185+ /// ```
186+ ///
187+ /// As mentioned above, columns referenced only by pushed-down filters may
188+ /// be absent from `projection`.
166189 async fn scan (
167190 & self ,
168191 state : & dyn Session ,
0 commit comments