From dc2f8505309e4e33088791b893eae52027f390c2 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Thu, 18 Jun 2026 08:08:39 -0400 Subject: [PATCH] feat: live progress + clean final count for bulk copy path The bulk path showed no progress during a load (only the final count). Emit an in-place counter (\r + rows) every 10k rows from the BulkSource adapter, which the caller pulls one row at a time, so it streams live. Prefix the final count print with \r so it starts a fresh line instead of concatenating onto the last tick (which produced a garbage row count like 3000035000). Verified: ticks emit at 10k/20k/30k, final row_count parses correctly, and pipekit's progress-collapse renders it as a single updating line. Co-Authored-By: Claude Opus 4.8 --- jrunner/src/main/java/jrunner/jrunner.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/jrunner/src/main/java/jrunner/jrunner.java b/jrunner/src/main/java/jrunner/jrunner.java index 70d9c4d..7abef0d 100644 --- a/jrunner/src/main/java/jrunner/jrunner.java +++ b/jrunner/src/main/java/jrunner/jrunner.java @@ -325,8 +325,10 @@ public class jrunner { BulkSource src = new BulkSource(rs, cols, dtn, trim); bulkCopy.writeToServer(src); bulkCopy.close(); - // print the count so the trailing " rows written" line is parseable - System.out.print(src.rowsWritten()); + // leading \r starts a fresh line so the count doesn't concatenate + // onto the last progress tick; the trailing " rows written" makes + // it parseable. + System.out.print("\r" + src.rowsWritten()); } catch (Exception e) { e.printStackTrace(); System.exit(0); @@ -604,6 +606,9 @@ public class jrunner { public Object[] getRowData() throws SQLServerException { rows++; + // live progress: emit an in-place counter every 10k rows (the + // caller pulls one row at a time, so this runs during the load). + if (rows % 10000 == 0) { System.out.print("\r" + rows); System.out.flush(); } Object[] row = new Object[cols]; try { for (int i = 1; i <= cols; i++) {