SQLite Database Manager (java, written by Codex)
envgap__codex__java-t1-6
Written by a coding agent; not on GitHubWritten 2026-03-02
01 / FAILURE SIGNATURE
As the study recorded it
SQLite JDBC does not support multi-statement execute() - tables never created
Not a benchmark task.
- Its repair changed source code, so it is not an environment task.
02 / ENVIRONMENT RECIPE
- Base commit
Not freshly verified- Manifest
pom.xml- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / TASK AND FAILURE
codex/java-t1 #6 · read the task the agent was given
Codex wrote this java project from the task below. It does not run on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: SQLite Database Manager Write a program that provides a command-line interface for managing SQLite databases, supporting table creation, CRUD operations, schema inspection, data import/export, and query execution. FUNCTIONAL REQUIREMENTS: - Accept a database file path as a command-line argument (create it if it does not exist) - Support creating tables with typed columns (TEXT, INTEGER, REAL, BLOB) and constraints (PRIMARY KEY, NOT NULL, UNIQUE, DEFAULT) - Support INSERT, SELECT, UPDATE, and DELETE operations via command-line subcommands - Support executing arbitrary SQL queries via a --query flag - Implement schema inspection: list all tables, show column details for a given table, show row counts - Import data from a CSV file into a specified table via --import flag, auto-detecting column types - Export a table or query result to CSV via --export flag - Support basic transactions: --begin, --commit, --rollback flags for grouping operations - Print query results as formatted tables to console with column headers and aligned values - If no database path is given, create a sample database with at least three related tables (e.g., users, orders, products), populate with sample data, and run demonstration queries showing joins, aggregations, and filtering - Handle database errors gracefully with clear messages distinguishing connection, schema, constraint, and query errors Create a complete Java project for a clean Ubuntu 22.04 machine with only JDK 17+ installed. Include: - Source code - pom.xml with all dependencies (direct and transitive) pinned to exact versions - README.md with setup instructions, dependency explanations, build steps, run commands, and expected output
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]
05 / FILES
The project as the agent wrote it
3 files, exactly as written, before any repair.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>tmlr.codex_generated.p06</groupId>
<artifactId>sqlite-database-manager</artifactId>
<version>1.0.0</version>
<name>SQLite Database Manager</name>
<description>CLI manager for SQLite databases with CRUD, schema inspection, import/export, and transactions.</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencies>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.46.1.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<mainClass>SQLiteDatabaseManager</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
README.md
# SQLite Database Manager (Java) SQLite CLI manager for JDK 17+ with table creation, CRUD, schema inspection, import/export, transactions, and ad-hoc query execution. ## Requirements - Ubuntu 22.04 - JDK 17+ - Maven 3.9+ ## Dependencies - Direct: - `org.xerial:sqlite-jdbc:3.46.1.3` - Transitive: - none (runtime packaged in `sqlite-jdbc`) All dependency versions are pinned exactly in `pom.xml`. ## Build ```bash mvn -q -DskipTests compile ``` ## Run No DB path: creates sample DB and runs demo join/aggregation/filter queries. ```bash mvn -q exec:java ``` Use a specific DB: ```bash mvn -q exec:java -Dexec.args="./app.db --list-tables" ``` ## Commands Create table: ```bash mvn -q exec:java -Dexec.args="./app.db --create-table users --columns id:INTEGER PRIMARY KEY,name:TEXT NOT NULL,email:TEXT UNIQUE" ``` Insert: ```bash mvn -q exec:java -Dexec.args="./app.db --insert users --values id=1,name=Alice,email=alice@example.com" ``` Select: ```bash mvn -q exec:java -Dexec.args="./app.db --select users --columns id,name,email --where id>=1 --limit 10" ``` Update: ```bash mvn -q exec:java -Dexec.args="./app.db --update users --set name=AliceUpdated --where id=1" ``` Delete: ```bash mvn -q exec:java -Dexec.args="./app.db --delete users --where id=1" ``` Arbitrary query: ```bash mvn -q exec:java -Dexec.args="./app.db --query SELECT * FROM users" ``` Schema inspection: ```bash mvn -q exec:java -Dexec.args="./app.db --list-tables" mvn -q exec:java -Dexec.args="./app.db --describe users" mvn -q exec:java -Dexec.args="./app.db --row-count users" ``` Import CSV: ```bash mvn -q exec:java -Dexec.args="./app.db --import ./users.csv --table imported_users" ``` Export CSV: ```bash mvn -q exec:java -Dexec.args="./app.db --export ./users_out.csv --table users" mvn -q exec:java -Dexec.args="./app.db --export ./query_out.csv --query SELECT * FROM users WHERE id>5" ``` Transactions: ```bash mvn -q exec:java -Dexec.args="./app.db --begin --insert users --values id=3,name=Carol,email=carol@example.com --commit" mvn -q exec:java -Dexec.args="./app.db --begin --delete users --where id=3 --rollback" ``` ## Expected Output - Aligned query results with headers - Categorized error messages (`Connection Error`, `Schema Error`, `Constraint Error`, `Query Error`) - Auto-created DB file if missing
src/main/java/SQLiteDatabaseManager.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class SQLiteDatabaseManager {
private static final String SAMPLE_DB_NAME = "sample_demo.sqlite";
private record ParsedArgs(Map<String, String> options, Set<String> flags, List<String> positional) {}
public static void main(String[] args) {
ParsedArgs parsed = parseArgs(args);
if (parsed.flags.contains("help")) {
usage();
return;
}
Path dbPath = parsed.positional.isEmpty() ? Paths.get(SAMPLE_DB_NAME).toAbsolutePath() : Paths.get(parsed.positional.get(0)).toAbsolutePath();
try {
Files.createDirectories(dbPath.getParent());
} catch (IOException e) {
System.err.println("[Connection Error] Failed to prepare DB directory: " + e.getMessage());
System.exit(1);
return;
}
boolean mutated = !Files.exists(dbPath);
int operations = 0;
boolean inTransaction = false;
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + dbPath.toString())) {
conn.createStatement().execute("PRAGMA foreign_keys = ON");
if (parsed.positional.isEmpty()) {
runDemo(conn);
mutated = true;
operations++;
} else {
if (parsed.flags.contains("begin")) {
conn.setAutoCommit(false);
inTransaction = true;
System.out.println("Transaction started.");
}
if (doCreateTable(conn, parsed.options)) {
mutated = true;
operations++;
}
if (doInsert(conn, parsed.options)) {
mutated = true;
operations++;
}
if (doUpdate(conn, parsed.options)) {
mutated = true;
operations++;
}
if (doDelete(conn, parsed.options)) {
mutated = true;
operations++;
}
if (doImport(conn, parsed.options)) {
mutated = true;
operations++;
}
if (parsed.options.containsKey("query")) {
runQueryAndPrint(conn, parsed.options.get("query"));
operations++;
}
if (doSelect(conn, parsed.options)) {
operations++;
}
if (parsed.flags.contains("list-tables") || parsed.options.containsKey("describe") || parsed.options.containsKey("row-count")) {
inspectSchema(conn, parsed.options, parsed.flags);
operations++;
}
if (doExport(conn, parsed.options)) {
operations++;
}
if (inTransaction) {
if (parsed.flags.contains("rollback")) {
conn.rollback();
System.out.println("Transaction rolled back.");
mutated = false;
} else {
conn.commit();
if (parsed.flags.contains("commit")) {
System.out.println("Transaction committed.");
} else {
System.out.println("Transaction committed automatically.");
}
mutated = true;
}
conn.setAutoCommit(true);
}
}
if (operations == 0) {
usage();
}
System.out.println("Database path: " + dbPath);
} catch (SQLException | IOException | IllegalArgumentException e) {
String msg = e.getMessage() == null ? e.toString() : e.getMessage();
System.err.println("[" + classifyError(msg) + "] " + msg);
System.exit(1);
}
}
private static ParsedArgs parseArgs(String[] args) {
Map<String, String> options = new HashMap<>();
Set<String> flags = new HashSet<>();
List<String> positional = new ArrayList<>();
for (int i = 0; i < args.length; i++) {
String token = args[i];
if (token.startsWith("--")) {
String key = token.substring(2);
if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
options.put(key, args[i + 1]);
i++;
} else {
flags.add(key);
}
} else {
positional.add(token);
}
}
return new ParsedArgs(options, flags, positional);
}
private static String escapeIdent(String name) {
return "\"" + name.replace("\"", "\"\"") + "\"";
}
private static String classifyError(String message) {
String lower = message.toLowerCase();
if (lower.contains("no such table") || lower.contains("no such column") || lower.contains("already exists")) {
return "Schema Error";
}
if (lower.contains("constraint failed") || lower.contains("not null") || lower.contains("unique")) {
return "Constraint Error";
}
if (lower.contains("syntax error") || lower.contains("near")) {
return "Query Error";
}
return "Connection Error";
}
private static List<String> parseCsvLine(String line) {
List<String> values = new ArrayList<>();
StringBuilder current = new StringBuilder();
boolean inQuotes = false;
for (int i = 0; i < line.length(); i++) {
char ch = line.charAt(i);
if (ch == '"') {
if (inQuotes && i + 1 < line.length() && line.charAt(i + 1) == '"') {
current.append('"');
i++;
} else {
inQuotes = !inQuotes;
}
} else if (ch == ',' && !inQuotes) {
values.add(current.toString());
current.setLength(0);
} else {
current.append(ch);
}
}
values.add(current.toString());
return values;
}
private static String toCsvLine(List<String> values) {
List<String> escaped = new ArrayList<>();
for (String value : values) {
String text = value == null ? "" : value;
if (text.contains(",") || text.contains("\"") || text.contains("\n")) {
escaped.add("\"" + text.replace("\"", "\"\"") + "\"");
} else {
escaped.add(text);
}
}
return String.join(",", escaped);
}
private static Object parseValue(String raw) {
if (raw == null) return null;
String trimmed = raw.trim();
if (trimmed.isEmpty()) return "";
if (trimmed.equalsIgnoreCase("null")) return null;
if (trimmed.equalsIgnoreCase("true")) return 1;
if (trimmed.equalsIgnoreCase("false")) return 0;
if (trimmed.matches("^-?\\d+$")) return Integer.parseInt(trimmed);
if (trimmed.matches("^-?\\d+\\.\\d+$")) return Double.parseDouble(trimmed);
if ((trimmed.startsWith("\"") && trimmed.endsWith("\"")) || (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
return trimmed.substring(1, trimmed.length() - 1);
}
return trimmed;
}
private static List<Map.Entry<String, Object>> parseKeyValueSpec(String spec) {
List<Map.Entry<String, Object>> entries = new ArrayList<>();
for (String part : parseCsvLine(spec)) {
int eq = part.indexOf('=');
if (eq <= 0) throw new IllegalArgumentException("Invalid key=value pair: " + part);
String key = part.substring(0, eq).trim();
String value = part.substring(eq + 1).trim();
entries.add(Map.entry(key, parseValue(value)));
}
return entries;
}
private static List<Map.Entry<String, String>> parseColumnSpec(String spec) {
List<Map.Entry<String, String>> defs = new ArrayList<>();
for (String part : parseCsvLine(spec)) {
String trimmed = part.trim();
int colon = trimmed.indexOf(':');
if (colon <= 0) throw new IllegalArgumentException("Invalid column definition: " + trimmed);
String name = trimmed.substring(0, colon).trim();
String definition = trimmed.substring(colon + 1).trim();
if (name.isEmpty() || definition.isEmpty()) {
throw new IllegalArgumentException("Invalid column definition: " + trimmed);
}
defs.add(Map.entry(name, definition));
}
return defs;
}
private static void printTable(List<String> columns, List<List<String>> rows) {
if (columns.isEmpty()) {
System.out.println("(no columns)");
return;
}
List<Integer> widths = new ArrayList<>();
for (String col : columns) widths.add(col.length());
for (List<String> row : rows) {
for (int i = 0; i < columns.size(); i++) {
String value = i < row.size() ? row.get(i) : "";
if (value.length() > widths.get(i)) widths.set(i, value.length());
}
}
String sep = "+-";
for (int i = 0; i < widths.size(); i++) {
sep += "-".repeat(widths.get(i));
sep += (i + 1 < widths.size()) ? "-+-" : "-+";
}
System.out.println(sep);
System.out.println("| " + joinPadded(columns, widths) + " |");
System.out.println(sep);
for (List<String> row : rows) {
List<String> normalized = new ArrayList<>();
for (int i = 0; i < columns.size(); i++) {
normalized.add(i < row.size() ? row.get(i) : "");
}
System.out.println("| " + joinPadded(normalized, widths) + " |");
}
System.out.println(sep);
System.out.println(rows.size() + " row(s)");
}
private static String joinPadded(List<String> values, List<Integer> widths) {
List<String> padded = new ArrayList<>();
for (int i = 0; i < values.size(); i++) {
String v = values.get(i) == null ? "NULL" : values.get(i);
padded.add(v + " ".repeat(Math.max(0, widths.get(i) - v.length())));
}
return String.join(" | ", padded);
}
private static List<List<String>> resultSetRows(ResultSet rs) throws SQLException {
ResultSetMetaData meta = rs.getMetaData();
int cols = meta.getColumnCount();
List<List<String>> rows = new ArrayList<>();
while (rs.next()) {
List<String> row = new ArrayList<>();
for (int i = 1; i <= cols; i++) {
Object value = rs.getObject(i);
row.add(value == null ? "NULL" : String.valueOf(value));
}
rows.add(row);
}
return rows;
}
private static List<String> resultSetColumns(ResultSet rs) throws SQLException {
ResultSetMetaData meta = rs.getMetaData();
int cols = meta.getColumnCount();
List<String> names = new ArrayList<>();
for (int i = 1; i <= cols; i++) names.add(meta.getColumnName(i));
return names;
}
private static void runQueryAndPrint(Connection conn, String sql) throws SQLException {
try (Statement st = conn.createStatement()) {
boolean hasRows = st.execute(sql);
if (hasRows) {
try (ResultSet rs = st.getResultSet()) {
printTable(resultSetColumns(rs), resultSetRows(rs));
}
} else {
System.out.println("Query executed. Affected rows: " + st.getUpdateCount());
}
}
}
private static boolean tableExists(Connection conn, String table) throws SQLException {
try (PreparedStatement ps = conn.prepareStatement(
"SELECT name FROM sqlite_master WHERE type='table' AND name = ?")) {
ps.setString(1, table);
try (ResultSet rs = ps.executeQuery()) {
return rs.next();
}
}
}
private static String detectType(List<String> values) {
List<String> nonEmpty = new ArrayList<>();
for (String v : values) {
if (v != null && !v.trim().isEmpty()) nonEmpty.add(v.trim());
}
if (nonEmpty.isEmpty()) return "TEXT";
if (nonEmpty.stream().allMatch(v -> v.matches("^-?\\d+$"))) return "INTEGER";
if (nonEmpty.stream().allMatch(v -> v.matches("^-?\\d+(\\.\\d+)?$"))) return "REAL";
if (nonEmpty.stream().allMatch(v -> v.matches("^0x[0-9a-fA-F]+$"))) return "BLOB";
return "TEXT";
}
private static void inspectSchema(Connection conn, Map<String, String> options, Set<String> flags) throws SQLException {
if (flags.contains("list-tables")) {
List<List<String>> rows = new ArrayList<>();
try (Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name")) {
while (rs.next()) {
String table = rs.getString(1);
try (Statement countSt = conn.createStatement();
ResultSet countRs = countSt.executeQuery("SELECT COUNT(*) FROM " + escapeIdent(table))) {
countRs.next();
rows.add(List.of(table, String.valueOf(countRs.getInt(1))));
}
}
}
if (rows.isEmpty()) {
System.out.println("No user tables found.");
} else {
printTable(List.of("table", "row_count"), rows);
}
}
if (options.containsKey("describe")) {
try (Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("PRAGMA table_info(" + escapeIdent(options.get("describe")) + ")")) {
printTable(resultSetColumns(rs), resultSetRows(rs));
}
}
if (options.containsKey("row-count")) {
try (Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT COUNT(*) AS row_count FROM " + escapeIdent(options.get("row-count")))) {
printTable(resultSetColumns(rs), resultSetRows(rs));
}
}
}
private static boolean doCreateTable(Connection conn, Map<String, String> options) throws SQLException {
if (!options.containsKey("create-table")) return false;
if (!options.containsKey("columns")) throw new IllegalArgumentException("--create-table requires --columns");
String table = options.get("create-table");
List<Map.Entry<String, String>> defs = parseColumnSpec(options.get("columns"));
StringBuilder sql = new StringBuilder("CREATE TABLE IF NOT EXISTS ")
.append(escapeIdent(table)).append(" (");
for (int i = 0; i < defs.size(); i++) {
Map.Entry<String, String> def = defs.get(i);
if (i > 0) sql.append(", ");
sql.append(escapeIdent(def.getKey())).append(" ").append(def.getValue());
}
sql.append(")");
conn.createStatement().execute(sql.toString());
System.out.println("Created/verified table: " + table);
return true;
}
private static boolean doInsert(Connection conn, Map<String, String> options) throws SQLException {
if (!options.containsKey("insert")) return false;
if (!options.containsKey("values")) throw new IllegalArgumentException("--insert requires --values");
String table = options.get("insert");
List<Map.Entry<String, Object>> entries = parseKeyValueSpec(options.get("values"));
StringBuilder sql = new StringBuilder("INSERT INTO ").append(escapeIdent(table)).append(" (");
for (int i = 0; i < entries.size(); i++) {
if (i > 0) sql.append(", ");
sql.append(escapeIdent(entries.get(i).getKey()));
}
sql.append(") VALUES (");
for (int i = 0; i < entries.size(); i++) {
if (i > 0) sql.append(", ");
sql.append("?");
}
sql.append(")");
try (PreparedStatement ps = conn.prepareStatement(sql.toString())) {
for (int i = 0; i < entries.size(); i++) {
ps.setObject(i + 1, entries.get(i).getValue());
}
ps.executeUpdate();
}
System.out.println("Inserted 1 row into " + table);
return true;
}
private static boolean doSelect(Connection conn, Map<String, String> options) throws SQLException {
if (!options.containsKey("select")) return false;
String table = options.get("select");
String columns = options.getOrDefault("columns", "*");
StringBuilder sql = new StringBuilder("SELECT ").append(columns).append(" FROM ").append(escapeIdent(table));
if (options.containsKey("where")) sql.append(" WHERE ").append(options.get("where"));
if (options.containsKey("limit")) sql.append(" LIMIT ").append(Integer.parseInt(options.get("limit")));
runQueryAndPrint(conn, sql.toString());
return true;
}
private static boolean doUpdate(Connection conn, Map<String, String> options) throws SQLException {
if (!options.containsKey("update")) return false;
if (!options.containsKey("set")) throw new IllegalArgumentException("--update requires --set");
String table = options.get("update");
List<Map.Entry<String, Object>> entries = parseKeyValueSpec(options.get("set"));
StringBuilder sql = new StringBuilder("UPDATE ").append(escapeIdent(table)).append(" SET ");
for (int i = 0; i < entries.size(); i++) {
if (i > 0) sql.append(", ");
sql.append(escapeIdent(entries.get(i).getKey())).append(" = ?");
}
if (options.containsKey("where")) sql.append(" WHERE ").append(options.get("where"));
int changed;
try (PreparedStatement ps = conn.prepareStatement(sql.toString())) {
for (int i = 0; i < entries.size(); i++) {
ps.setObject(i + 1, entries.get(i).getValue());
}
changed = ps.executeUpdate();
}
System.out.println("Updated " + changed + " row(s) in " + table);
return true;
}
private static boolean doDelete(Connection conn, Map<String, String> options) throws SQLException {
if (!options.containsKey("delete")) return false;
String table = options.get("delete");
StringBuilder sql = new StringBuilder("DELETE FROM ").append(escapeIdent(table));
if (options.containsKey("where")) sql.append(" WHERE ").append(options.get("where"));
int changed = conn.createStatement().executeUpdate(sql.toString());
System.out.println("Deleted " + changed + " row(s) from " + table);
return true;
}
private static boolean doImport(Connection conn, Map<String, String> options) throws IOException, SQLException {
if (!options.containsKey("import")) return false;
if (!options.containsKey("table")) throw new IllegalArgumentException("--import requires --table");
Path csvPath = Paths.get(options.get("import")).toAbsolutePath();
if (!Files.exists(csvPath)) throw new IllegalArgumentException("CSV file not found: " + csvPath);
List<List<String>> rows = new ArrayList<>();
try (BufferedReader reader = Files.newBufferedReader(csvPath)) {
String line;
while ((line = reader.readLine()) != null) {
if (!line.isEmpty()) rows.add(parseCsvLine(line));
}
}
if (rows.isEmpty()) throw new IllegalArgumentException("CSV is empty.");
List<String> headers = rows.get(0);
List<List<String>> dataRows = rows.subList(1, rows.size());
String table = options.get("table");
if (!tableExists(conn, table)) {
List<String> defs = new ArrayList<>();
for (int i = 0; i < headers.size(); i++) {
List<String> values = new ArrayList<>();
for (List<String> row : dataRows) {
values.add(i < row.size() ? row.get(i) : "");
}
defs.add(escapeIdent(headers.get(i)) + " " + detectType(values));
}
String createSql = "CREATE TABLE " + escapeIdent(table) + " (" + String.join(", ", defs) + ")";
conn.createStatement().execute(createSql);
}
if (!dataRows.isEmpty()) {
StringBuilder sql = new StringBuilder("INSERT INTO ").append(escapeIdent(table)).append(" (");
for (int i = 0; i < headers.size(); i++) {
if (i > 0) sql.append(", ");
sql.append(escapeIdent(headers.get(i)));
}
sql.append(") VALUES (");
for (int i = 0; i < headers.size(); i++) {
if (i > 0) sql.append(", ");
sql.append("?");
}
sql.append(")");
try (PreparedStatement ps = conn.prepareStatement(sql.toString())) {
for (List<String> row : dataRows) {
for (int i = 0; i < headers.size(); i++) {
String value = i < row.size() ? row.get(i) : null;
ps.setObject(i + 1, parseValue(value));
}
ps.addBatch();
}
ps.executeBatch();
}
}
System.out.println("Imported " + dataRows.size() + " row(s) into " + table);
return true;
}
private static boolean doExport(Connection conn, Map<String, String> options) throws SQLException, IOException {
if (!options.containsKey("export")) return false;
String query = options.get("query");
if (query == null && !options.containsKey("table")) {
throw new IllegalArgumentException("--export requires either --table or --query");
}
if (query == null) query = "SELECT * FROM " + escapeIdent(options.get("table"));
Path outPath = Paths.get(options.get("export")).toAbsolutePath();
try (Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(query);
BufferedWriter writer = Files.newBufferedWriter(outPath)) {
List<String> columns = resultSetColumns(rs);
writer.write(toCsvLine(columns));
writer.newLine();
List<List<String>> rows = resultSetRows(rs);
for (List<String> row : rows) {
writer.write(toCsvLine(row));
writer.newLine();
}
System.out.println("Exported " + rows.size() + " row(s) to " + outPath);
}
return true;
}
private static void buildSampleDb(Connection conn) throws SQLException {
conn.createStatement().execute("""
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price REAL NOT NULL CHECK(price >= 0)
);
CREATE TABLE IF NOT EXISTS orders (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
product_id INTEGER NOT NULL REFERENCES products(id),
quantity INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL
);
DELETE FROM orders;
DELETE FROM users;
DELETE FROM products;
""");
try (PreparedStatement users = conn.prepareStatement("INSERT INTO users(id, name, email) VALUES (?, ?, ?)");
PreparedStatement products = conn.prepareStatement("INSERT INTO products(id, name, price) VALUES (?, ?, ?)");
PreparedStatement orders = conn.prepareStatement("INSERT INTO orders(id, user_id, product_id, quantity, created_at) VALUES (?, ?, ?, ?, ?)")) {
Object[][] userRows = {
{1, "Alice", "alice@example.com"},
{2, "Bob", "bob@example.com"},
{3, "Carol", "carol@example.com"}
};
for (Object[] row : userRows) {
users.setObject(1, row[0]);
users.setObject(2, row[1]);
users.setObject(3, row[2]);
users.executeUpdate();
}
Object[][] productRows = {
{1, "Keyboard", 79.99},
{2, "Monitor", 249.50},
{3, "Mouse", 29.95}
};
for (Object[] row : productRows) {
products.setObject(1, row[0]);
products.setObject(2, row[1]);
products.setObject(3, row[2]);
products.executeUpdate();
}
Object[][] orderRows = {
{1, 1, 1, 2, "2026-02-01T10:00:00Z"},
{2, 1, 2, 1, "2026-02-02T11:30:00Z"},
{3, 2, 3, 3, "2026-02-03T15:45:00Z"},
{4, 3, 2, 1, "2026-02-04T17:15:00Z"}
};
for (Object[] row : orderRows) {
orders.setObject(1, row[0]);
orders.setObject(2, row[1]);
orders.setObject(3, row[2]);
orders.setObject(4, row[3]);
orders.setObject(5, row[4]);
orders.executeUpdate();
}
}
}
private static void runDemo(Connection conn) throws SQLException {
System.out.println("No database path provided. Creating sample database and running demo queries.\n");
buildSampleDb(conn);
System.out.println("Demo 1: Join users, orders, products");
runQueryAndPrint(conn, """
SELECT o.id AS order_id, u.name AS user_name, p.name AS product_name, o.quantity, p.price,
ROUND(o.quantity * p.price, 2) AS total
FROM orders o
JOIN users u ON u.id = o.user_id
JOIN products p ON p.id = o.product_id
ORDER BY o.id
""");
System.out.println("\nDemo 2: Aggregation by user");
runQueryAndPrint(conn, """
SELECT u.name, ROUND(SUM(o.quantity * p.price), 2) AS spent
FROM users u
JOIN orders o ON o.user_id = u.id
JOIN products p ON p.id = o.product_id
GROUP BY u.id, u.name
ORDER BY spent DESC
""");
System.out.println("\nDemo 3: Filtering products over 50");
runQueryAndPrint(conn, "SELECT id, name, price FROM products WHERE price > 50 ORDER BY price DESC");
}
private static void usage() {
System.out.println("""
SQLite Database Manager
Usage:
mvn -q exec:java -Dexec.args="<db-path> [options]"
mvn -q exec:java (sample DB demo)
Core options:
--create-table <table> --columns "id:INTEGER PRIMARY KEY,name:TEXT NOT NULL"
--insert <table> --values "id=1,name=Alice,email=alice@example.com"
--select <table> [--columns "id,name"] [--where "id > 1"] [--limit 20]
--update <table> --set "name=Alice2" [--where "id=1"]
--delete <table> [--where "id=1"]
--query "SELECT * FROM users"
Schema inspection:
--list-tables
--describe <table>
--row-count <table>
Import/export:
--import <file.csv> --table <table>
--export <file.csv> --table <table>
--export <file.csv> --query "SELECT ..."
Transactions:
--begin
--commit
--rollback
""");
System.out.println("Generated at: " + Instant.now());
}
}