Skip to content

Commit 330e9c5

Browse files
Fix: MemTable LIMIT ignored with reordered projections
1 parent 7cbc6b4 commit 330e9c5

2 files changed

Lines changed: 83 additions & 4 deletions

File tree

datafusion/datasource/src/memory.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ impl DataSource for MemorySourceConfig {
249249
self.original_schema(),
250250
Some(new_projections),
251251
)
252-
.map(|s| Arc::new(s) as Arc<dyn DataSource>)
252+
.map(|s| Arc::new(s.with_limit(self.fetch)) as Arc<dyn DataSource>)
253253
})
254254
.transpose()
255255
}
@@ -897,6 +897,42 @@ mod tests {
897897
Ok(())
898898
}
899899

900+
/// Test that `try_swapping_with_projection` preserves the `fetch` limit.
901+
/// Regression test for <https://github.com/apache/datafusion/issues/21176>
902+
#[test]
903+
fn try_swapping_with_projection_preserves_fetch() {
904+
use datafusion_physical_expr::projection::ProjectionExprs;
905+
906+
let schema = Arc::new(Schema::new(vec![
907+
Field::new("a", DataType::Int32, false),
908+
Field::new("b", DataType::Utf8, false),
909+
Field::new("c", DataType::Int64, false),
910+
]));
911+
let partitions: Vec<Vec<RecordBatch>> = vec![vec![batch(10)]];
912+
let source = MemorySourceConfig::try_new(&partitions, schema.clone(), None)
913+
.unwrap()
914+
.with_limit(Some(5));
915+
916+
assert_eq!(source.fetch, Some(5));
917+
918+
// Create a projection that reorders columns: [c, a] (indices 2, 0)
919+
let projection = ProjectionExprs::from_indices(&[2, 0], &schema);
920+
let swapped = source
921+
.try_swapping_with_projection(&projection)
922+
.unwrap()
923+
.expect("should return Some");
924+
let new_source = swapped
925+
.as_any()
926+
.downcast_ref::<MemorySourceConfig>()
927+
.unwrap();
928+
929+
assert_eq!(
930+
new_source.fetch,
931+
Some(5),
932+
"fetch limit must be preserved after projection pushdown"
933+
);
934+
}
935+
900936
#[tokio::test]
901937
async fn values_empty_case() -> Result<()> {
902938
let schema = aggr_test_schema();

datafusion/sqllogictest/test_files/limit.slt

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,7 @@ explain select * from testSubQueryLimit as t1 join (select * from testSubQueryLi
729729
----
730730
logical_plan
731731
01)Limit: skip=0, fetch=10
732-
02)--Cross Join:
732+
02)--Cross Join:
733733
03)----SubqueryAlias: t1
734734
04)------Limit: skip=0, fetch=10
735735
05)--------TableScan: testsubquerylimit projection=[a, b], fetch=10
@@ -754,7 +754,7 @@ explain select * from testSubQueryLimit as t1 join (select * from testSubQueryLi
754754
----
755755
logical_plan
756756
01)Limit: skip=0, fetch=2
757-
02)--Cross Join:
757+
02)--Cross Join:
758758
03)----SubqueryAlias: t1
759759
04)------Limit: skip=0, fetch=2
760760
05)--------TableScan: testsubquerylimit projection=[a, b], fetch=2
@@ -867,7 +867,7 @@ limit 1000;
867867

868868
# Config reset
869869

870-
# The SLT runner sets `target_partitions` to 4 instead of using the default, so
870+
# The SLT runner sets `target_partitions` to 4 instead of using the default, so
871871
# reset it explicitly.
872872
statement ok
873873
set datafusion.execution.target_partitions = 4;
@@ -927,3 +927,46 @@ DROP TABLE t;
927927
# Tear down src_table table:
928928
statement ok
929929
DROP TABLE src_table;
930+
931+
# LIMIT must work when SELECT projects columns in different order than table schema
932+
933+
statement ok
934+
CREATE TABLE t21176 (col_a TEXT, col_b DOUBLE, col_c TEXT) AS VALUES
935+
('a-0', 0, 'c-0'), ('a-1', 1, 'c-1'), ('a-2', 2, 'c-2'), ('a-3', 3, 'c-3'),
936+
('a-4', 4, 'c-4'), ('a-5', 5, 'c-5'), ('a-6', 6, 'c-6'), ('a-7', 7, 'c-7'),
937+
('a-8', 8, 'c-8'), ('a-9', 9, 'c-9'), ('a-10', 10, 'c-10'), ('a-11', 11, 'c-11'),
938+
('a-12', 12, 'c-12'), ('a-13', 13, 'c-13'), ('a-14', 14, 'c-14'), ('a-15', 15, 'c-15'),
939+
('a-16', 16, 'c-16'), ('a-17', 17, 'c-17'), ('a-18', 18, 'c-18'), ('a-19', 19, 'c-19');
940+
941+
# Schema-order SELECT with LIMIT should return 5 rows
942+
query RT rowsort
943+
SELECT col_b, col_c FROM t21176 LIMIT 5;
944+
----
945+
0 c-0
946+
1 c-1
947+
2 c-2
948+
3 c-3
949+
4 c-4
950+
951+
# Reverse-order SELECT with LIMIT should also return 5 rows (not 20)
952+
query TR rowsort
953+
SELECT col_c, col_b FROM t21176 LIMIT 5;
954+
----
955+
c-0 0
956+
c-1 1
957+
c-2 2
958+
c-3 3
959+
c-4 4
960+
961+
# Single column reverse SELECT with LIMIT
962+
query T rowsort
963+
SELECT col_c FROM t21176 LIMIT 5;
964+
----
965+
c-0
966+
c-1
967+
c-2
968+
c-3
969+
c-4
970+
971+
statement ok
972+
DROP TABLE t21176;

0 commit comments

Comments
 (0)