Skip to content

Commit b75df6f

Browse files
fix: Prevent CLI crash on wide tables (#21721)
## Which issue does this PR close? <!-- We generally require a GitHub issue to be filed for all bug fixes and enhancements and this helps us generate change logs for our releases. You can link an issue to this PR using the GitHub syntax. For example `Closes #123` indicates that this PR will close issue #123. --> - Closes #21709 ## Rationale for this change <!-- Why are you proposing this change? If this is already explained clearly in the issue then this section is not needed. Explaining clearly why changes are proposed helps reviewers understand your changes and offer better suggestions for fixes. --> The `keep_only_maxrows` function panics on wide tables, format string treats the spaces variable as an index and the new code repeats the space character directly. This prevents the format argument error. ## What changes are included in this PR? <!-- There is no need to duplicate the description in the issue here but it is sometimes worth providing a summary of the individual changes in this PR. --> - replaces the format string in `keep_only_maxrows`. - adds `print_maxrows_limited_wide_table` unit test. - adds `test_cli_wide_result_set_no_crash` integration test. - adds a wide result set snapshot file. ## Are these changes tested? <!-- We typically require tests for all PRs in order to: 1. Prevent the code from being accidentally broken by subsequent changes 2. Serve as another way to document the expected behavior of the code If tests are not included in your PR, please explain why (for example, are they covered by existing tests)? --> Yes. I added unit and integration tests. The unit test passes a ten column schema to `keep_only_maxrows` and the integration test runs a wide query with a small row limit. These tests verify your format bug fix. ## Are there any user-facing changes? No <!-- If there are user-facing changes then we may require documentation to be updated before approving the PR. --> <!-- If there are any breaking changes to public APIs, please add the `api change` label. -->
1 parent 8a650f5 commit b75df6f

3 files changed

Lines changed: 85 additions & 1 deletion

File tree

datafusion-cli/src/print_format.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ fn keep_only_maxrows(s: &str, maxrows: usize) -> String {
9797
let last_line = &lines[lines.len() - 1]; // bottom border line
9898

9999
let spaces = last_line.len().saturating_sub(4);
100-
let dotted_line = format!("| .{:<spaces$}|", "", spaces = spaces);
100+
let dotted_line = format!("| .{}|", " ".repeat(spaces));
101101

102102
let mut result = lines[0..(maxrows + 3)].to_vec(); // Keep top border and `maxrows` lines
103103
result.extend(vec![dotted_line; 3]); // Append ... lines
@@ -632,6 +632,41 @@ mod tests {
632632
.unwrap()
633633
}
634634

635+
#[test]
636+
fn print_maxrows_limited_wide_table() {
637+
let output = PrintBatchesTest::new()
638+
.with_format(PrintFormat::Table)
639+
.with_batches(vec![wide_column_batch()])
640+
.with_maxrows(MaxRows::Limited(1))
641+
.run();
642+
assert_snapshot!(output, @r"
643+
+----+----+----+----+----+----+----+----+----+----+
644+
| c0 | c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 |
645+
+----+----+----+----+----+----+----+----+----+----+
646+
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
647+
| . |
648+
| . |
649+
| . |
650+
+----+----+----+----+----+----+----+----+----+----+
651+
");
652+
}
653+
654+
/// return a schema with many columns (to exercise wide table formatting)
655+
fn wide_column_schema() -> SchemaRef {
656+
let fields: Vec<Field> = (0..10)
657+
.map(|i| Field::new(format!("c{i}"), DataType::Int32, false))
658+
.collect();
659+
Arc::new(Schema::new(fields))
660+
}
661+
662+
/// return a batch with many columns and three rows
663+
fn wide_column_batch() -> RecordBatch {
664+
let arrays: Vec<Arc<dyn arrow::array::Array>> = (0..10)
665+
.map(|_| Arc::new(Int32Array::from(vec![0, 1, 2])) as _)
666+
.collect();
667+
RecordBatch::try_new(wide_column_schema(), arrays).unwrap()
668+
}
669+
635670
/// Slice the record batch into 2 batches
636671
fn split_batch(batch: &RecordBatch) -> Vec<RecordBatch> {
637672
assert!(batch.num_rows() > 1);

datafusion-cli/tests/cli_integration.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,23 @@ fn test_cli_with_unbounded_memory_pool() {
287287
assert_cmd_snapshot!(cmd);
288288
}
289289

290+
#[test]
291+
fn test_cli_wide_result_set_no_crash() {
292+
let mut settings = make_settings();
293+
294+
settings.set_snapshot_suffix("wide_result_set");
295+
296+
let _bound = settings.bind_to_scope();
297+
298+
let mut cmd = cli();
299+
let sql = "SELECT v1 as c0, v1+1 as c1, v1+2 as c2, v1+3 as c3, v1+4 as c4, \
300+
v1+5 as c5, v1+6 as c6, v1+7 as c7, v1+8 as c8, v1+9 as c9 \
301+
FROM generate_series(1, 100) as t1(v1);";
302+
cmd.args(["--maxrows", "5", "--command", sql]);
303+
304+
assert_cmd_snapshot!(cmd);
305+
}
306+
290307
#[tokio::test]
291308
async fn test_cli() {
292309
if env::var("TEST_STORAGE_INTEGRATION").is_err() {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
source: datafusion-cli/tests/cli_integration.rs
3+
assertion_line: 307
4+
info:
5+
program: datafusion-cli
6+
args:
7+
- "--maxrows"
8+
- "5"
9+
- "--command"
10+
- "SELECT v1 as c0, v1+1 as c1, v1+2 as c2, v1+3 as c3, v1+4 as c4, v1+5 as c5, v1+6 as c6, v1+7 as c7, v1+8 as c8, v1+9 as c9 FROM generate_series(1, 100) as t1(v1);"
11+
---
12+
success: true
13+
exit_code: 0
14+
----- stdout -----
15+
[CLI_VERSION]
16+
+----+----+----+----+----+----+----+----+----+----+
17+
| c0 | c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 |
18+
+----+----+----+----+----+----+----+----+----+----+
19+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
20+
| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
21+
| 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
22+
| 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
23+
| 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
24+
| . |
25+
| . |
26+
| . |
27+
+----+----+----+----+----+----+----+----+----+----+
28+
100 row(s) fetched. (First 5 displayed. Use --maxrows to adjust)
29+
[ELAPSED]
30+
31+
32+
----- stderr -----

0 commit comments

Comments
 (0)