diff --git a/jrunner/src/main/java/jrunner/jrunner.java b/jrunner/src/main/java/jrunner/jrunner.java index ce244b3..b2e09d3 100644 --- a/jrunner/src/main/java/jrunner/jrunner.java +++ b/jrunner/src/main/java/jrunner/jrunner.java @@ -70,6 +70,7 @@ public class jrunner { msg = msg + nl + "-b bulk copy into destination (SQL Server dest only)"; msg = msg + nl + "-f output format (csv, tsv, table, json) - default: csv"; msg = msg + nl + "--passfile path to the connection alias file - default: ~/.jrunnerpass"; + msg = msg + nl + "--strict exit 1 on failure (default exits 0, for legacy callers)"; msg = msg + nl + "--help info"; msg = msg + nl + ""; msg = msg + nl + "Prefer -sc/-dc aliases over -scp/-dcp: a password given on the"; @@ -83,6 +84,12 @@ public class jrunner { //---------------------------------------parse args into variables------------------------------------------------- + // Pre-scan: -sq can fail while the loop is still running, and it must + // honour --strict regardless of where the flag sits in argv. + for (String a : args) { + if (a.equals("--strict")) strictExit = true; + } + for (int i = 0; i < args.length; i = i +1 ){ switch (args[i]) { //source connection alias @@ -126,7 +133,7 @@ public class jrunner { catch (Exception e) { //System.out.println(nl + "error reasing source sql file: " + printStackTrace()); e.printStackTrace(); - System.exit(0); + die(); return; } break; @@ -150,6 +157,9 @@ public class jrunner { case "--passfile": passFilePath = args[i+1]; break; + //exit non-zero on failure (handled in the pre-scan above) + case "--strict": + break; case "-v": System.out.println(msg); return; @@ -223,7 +233,7 @@ public class jrunner { Class.forName("com.ibm.as400.access.AS400JDBCDriver"); } catch (ClassNotFoundException cnf) { System.out.println("The AS400 JDBC driver did not load"); - System.exit(0); + die(); } //-------------------------------------------establish connections------------------------------------------------- @@ -245,7 +255,7 @@ public class jrunner { } catch (SQLException e) { System.out.println("issue connecting to source:"); e.printStackTrace(); - System.exit(0); + die(); } if (!queryMode) { System.out.println(" ✅ source database"); @@ -257,7 +267,7 @@ public class jrunner { } catch (SQLException e) { System.out.println("issue connecting to destination:"); e.printStackTrace(); - System.exit(0); + die(); } System.out.println(" ✅ destination database"); } @@ -276,7 +286,7 @@ public class jrunner { } catch (SQLException e) { System.out.println("issue retrieving rows from source:"); e.printStackTrace(); - System.exit(0); + die(); } //---------------------------------------build meta--------------------------------------------------------------- @@ -290,7 +300,7 @@ public class jrunner { dtn = new String[cols + 1]; } catch (SQLException e) { e.printStackTrace(); - System.exit(0); + die(); } try { for (int i = 1; i <= cols; i++){ @@ -301,7 +311,7 @@ public class jrunner { } } catch (SQLException e) { e.printStackTrace(); - System.exit(0); + die(); } //-------------------------clear the target table if requeted---------------------------------------------------- if (!queryMode && clear) { @@ -314,7 +324,7 @@ public class jrunner { } catch (SQLException e) { e.printStackTrace(); System.out.println(sql); - System.exit(0); + die(); } } if (queryMode) { @@ -323,7 +333,7 @@ public class jrunner { outputQueryResults(rs, cols, dtn, outputFormat); } catch (SQLException e) { e.printStackTrace(); - System.exit(0); + die(); } } else if (bulk && dcu.toLowerCase().startsWith("jdbc:sqlserver:")) { //-------------------------------bulk copy (SQL Server dest)------------------------------------------------- @@ -347,7 +357,7 @@ public class jrunner { System.out.print("\r" + src.rowsWritten()); } catch (Exception e) { e.printStackTrace(); - System.exit(0); + die(); } } else if (bulk && dcu.toLowerCase().startsWith("jdbc:postgresql:")) { //-------------------------------bulk copy (COPY, Postgres dest)-------------------------------------------- @@ -389,7 +399,7 @@ public class jrunner { System.out.print("\r" + rows); } catch (Exception e) { e.printStackTrace(); - System.exit(0); + die(); } } else { System.out.println("------------row count-------------------------------------"); @@ -523,7 +533,7 @@ public class jrunner { } catch (SQLException e) { e.printStackTrace(); System.out.println(sql); - System.exit(0); + die(); } sql = ""; } @@ -538,12 +548,12 @@ public class jrunner { } catch (SQLException e) { e.printStackTrace(); System.out.println(sql); - System.exit(0); + die(); } } } catch (SQLException e) { e.printStackTrace(); - System.exit(0); + die(); } } //System.out.println(sql); @@ -767,6 +777,17 @@ public class jrunner { return value; } + // Historically every error path did printStackTrace() then System.exit(0), + // so a failed run was indistinguishable from a successful one to any + // caller checking $?. 112 /opt/sync scripts run under `set -e` against + // that behaviour, so flipping it unconditionally would change them all at + // once; --strict makes the correct exit code opt-in until they're audited. + private static boolean strictExit = false; + + private static void die() { + System.exit(strictExit ? 1 : 0); + } + private static String escapeTSV(String value) { return value.replaceAll("\t", " ").replaceAll("\n", " ").replaceAll("\r", " "); }