{"record":{"id":"5669d581f8af3fa3","repo":"tursodatabase/turso","slug":"sql-command-cannot-be-null","errorCode":null,"errorMessage":"SQL command cannot be null","messagePattern":"SQL command cannot be null","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/jdbc4/JDBC4Statement.java","lineNumber":265,"sourceCode":"    // TODO\n    return 0;\n  }\n\n  @Override\n  public int getResultSetConcurrency() {\n    return resultSetConcurrency;\n  }\n\n  @Override\n  public int getResultSetType() {\n    return resultSetType;\n  }\n\n  @Override\n  public void addBatch(String sql) throws SQLException {\n    ensureOpen();\n    if (sql == null) {\n      throw new SQLException(\"SQL command cannot be null\");\n    }\n    batchCommands.add(sql);\n  }\n\n  @Override\n  public void clearBatch() throws SQLException {\n    ensureOpen();\n    batchCommands.clear();\n  }\n\n  // TODO: let's make this batch operation atomic\n  @Override\n  public int[] executeBatch() throws SQLException {\n    ensureOpen();\n\n    int[] updateCounts = new int[batchCommands.size()];\n    List<String> failedCommands = new ArrayList<>();\n","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4Statement.java#L247-L283","documentation":"JDBC4Statement.addBatch(String) first checks the statement is open (ensureOpen), then rejects a null SQL string with SQLException(\"SQL command cannot be null\") before appending to batchCommands. clearBatch empties the list and executeBatch runs it; the null check exists so a null never silently lands in the batch.","triggerScenarios":"stmt.addBatch(null); loops building batches from lists/maps where some entries are null; SQL builders that return null on an error path; conditional generation where the 'no SQL produced' case yields null instead of being skipped.","commonSituations":"Batch importers iterating nullable records; refactors that moved null-filtering after the addBatch call; test code passing null to mean 'skip this one'.","solutions":["Null-check (and ideally blank-check) each SQL string before addBatch","Skip the record entirely when SQL generation produced nothing","Guard the whole batch loop when the source collection may contain nulls"],"exampleFix":"// before\nfor (String sql : statements) {\n  stmt.addBatch(sql); // NPE-adjacent entry -> SQLException on null\n}\n\n// after\nfor (String sql : statements) {\n  if (sql == null || sql.isBlank()) continue;\n  stmt.addBatch(sql);\n}","handlingStrategy":"validation","validationCode":"for (String sql : statements) {\n  if (sql != null && !sql.isBlank()) {\n    stmt.addBatch(sql);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  stmt.addBatch(sql);\n} catch (SQLException e) {\n  if (\"SQL command cannot be null\".equals(e.getMessage())) {\n    continue; // skip the offending entry\n  }\n  throw e;\n}","preventionTips":["Filter null/blank SQL at the source collection before batching","Have SQL builders return Optional<String> or a sentinel instead of null","Validate batch entries in one place instead of relying on the driver's check"],"tags":["java","jdbc","turso","batch","null-check","validation"],"backgroundTag":"null-argument","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}