SQL Playground — Java source
Run real SQL on sample datasets - or your own schema - right in the browser. Write queries, see formatted results instantly, and export or share them. Powered by sql.js (SQLite WASM); 100% client-side.
This is the Java implementation — the same logic the interactive tool runs, in a shareable, citable form.
// sql-playground — SQL statement splitting, read-only classification, CSV / Markdown serialization (Java).
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public final class SqlPlayground {
private static final Pattern READ_ONLY =
Pattern.compile("^(SELECT|WITH|VALUES|EXPLAIN|PRAGMA)\\b", Pattern.CASE_INSENSITIVE);
// Split on ';' outside '...' literals; a doubled '' inside a string is an escaped quote.
public static List<String> splitStatements(String sql) {
List<String> stmts = new ArrayList<>();
StringBuilder current = new StringBuilder();
boolean inString = false;
for (int i = 0; i < sql.length(); i++) {
char ch = sql.charAt(i);
if (inString) {
current.append(ch);
if (ch == '\'') {
if (i + 1 < sql.length() && sql.charAt(i + 1) == '\'') current.append(sql.charAt(++i)); // '' escape
else inString = false;
}
} else if (ch == '\'') { inString = true; current.append(ch); }
else if (ch == ';') {
String t = current.toString().trim();
if (!t.isEmpty()) stmts.add(t);
current.setLength(0);
} else current.append(ch);
}
String t = current.toString().trim();
if (!t.isEmpty()) stmts.add(t);
return stmts;
}
// A leading SELECT / WITH / VALUES / EXPLAIN / PRAGMA marks the statement read-only.
public static boolean isReadOnlyStatement(String stmt) { return READ_ONLY.matcher(stmt.trim()).find(); }
// RFC-4180-ish CSV field: quote on , " CR or LF, doubling embedded quotes; null = SQL NULL.
static String csvField(String cell) {
String v = cell == null ? "NULL" : cell;
return v.matches("[^,\"\\r\\n]*") ? v : '"' + v.replace("\"", "\"\"") + '"';
}
// Markdown cell: a null is SQL NULL; pipes are backslash-escaped.
static String mdCell(String cell) { return (cell == null ? "NULL" : cell).replace("|", "\\|"); }
public static String rowsToCsv(String[] columns, String[][] rows) {
StringBuilder out = new StringBuilder();
appendCsvLine(out, columns);
for (String[] row : rows) appendCsvLine(out, row);
return out.toString();
}
private static void appendCsvLine(StringBuilder out, String[] cells) {
for (int c = 0; c < cells.length; c++) out.append(c > 0 ? "," : "").append(csvField(cells[c]));
out.append('\n');
}
public static String rowsToMarkdown(String[] columns, String[][] rows) {
StringBuilder out = new StringBuilder(mdRow(columns)).append('\n').append('|').append(" --- |".repeat(columns.length)).append('\n');
for (String[] row : rows) out.append(mdRow(row)).append('\n');
return out.toString();
}
private static String mdRow(String[] cells) {
StringBuilder row = new StringBuilder("|");
for (String cell : cells) row.append(' ').append(mdCell(cell)).append(" |");
return row.toString();
}
public static void main(String[] args) {
String script = "CREATE TABLE t (id INT); SELECT * FROM t WHERE note = 'a''b;c' ; ;DROP TABLE t";
for (String s : splitStatements(script))
System.out.printf("[%s] %s%n", isReadOnlyStatement(s) ? "read-only" : "write", s);
String[] cols = {"name", "note"};
String[][] rows = {{"O'Brien", "has, \"quotes\""}, {null, "pipe|inside"}};
System.out.println("\nCSV:");
System.out.print(rowsToCsv(cols, rows));
System.out.print(rowsToMarkdown(cols, rows));
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →