001package edu.pdx.cs.joy.jdbc; 002 003import java.io.File; 004import java.sql.*; 005 006/** 007 * A command-line program that executes SQL statements against an H2 database. 008 * Supports all CRUD operations (INSERT, SELECT, UPDATE, DELETE) and displays 009 * results in a human-readable format. 010 */ 011public class ExecuteH2DatabaseStatement { 012 013 /** 014 * Main method that takes a database file path and SQL statement as arguments. 015 * 016 * @param args command line arguments: args[0] = database file path, args[1] = SQL statement 017 * @throws SQLException if a database error occurs 018 */ 019 public static void main(String[] args) throws SQLException { 020 if (args.length < 2) { 021 System.err.println("Missing required arguments"); 022 System.err.println("Usage: java ExecuteH2DatabaseStatement <database-file-path> <sql-statement>"); 023 System.err.println(); 024 System.err.println("Examples:"); 025 System.err.println(" SELECT: java ExecuteH2DatabaseStatement mydb.db \"SELECT * FROM users\""); 026 System.err.println(" INSERT: java ExecuteH2DatabaseStatement mydb.db \"INSERT INTO users (name) VALUES ('John')\""); 027 System.err.println(" UPDATE: java ExecuteH2DatabaseStatement mydb.db \"UPDATE users SET name='Jane' WHERE id=1\""); 028 System.err.println(" DELETE: java ExecuteH2DatabaseStatement mydb.db \"DELETE FROM users WHERE id=1\""); 029 return; 030 } 031 032 String dbFilePath = args[0]; 033 String sqlStatement = args[1]; 034 035 File dbFile = new File(dbFilePath); 036 System.out.println("Connecting to H2 database: " + dbFile.getAbsolutePath()); 037 System.out.println("Executing SQL: " + sqlStatement); 038 System.out.println(); 039 040 try (Connection connection = H2DatabaseHelper.createFileBasedConnection(dbFile)) { 041 executeStatement(connection, sqlStatement); 042 } 043 } 044 045 /** 046 * Executes a SQL statement and displays the results. 047 * 048 * @param connection the database connection 049 * @param sql the SQL statement to execute 050 * @throws SQLException if a database error occurs 051 */ 052 private static void executeStatement(Connection connection, String sql) throws SQLException { 053 try (Statement statement = connection.createStatement()) { 054 // Determine if this is a query (SELECT) or update (INSERT/UPDATE/DELETE) 055 boolean isQuery = statement.execute(sql); 056 057 if (isQuery) { 058 // Handle SELECT queries 059 try (ResultSet resultSet = statement.getResultSet()) { 060 displayResultSet(resultSet); 061 } 062 } else { 063 // Handle INSERT, UPDATE, DELETE 064 int rowsAffected = statement.getUpdateCount(); 065 System.out.println("Statement executed successfully"); 066 System.out.println("Rows affected: " + rowsAffected); 067 } 068 } 069 } 070 071 /** 072 * Displays a ResultSet in a formatted table. 073 * 074 * @param resultSet the result set to display 075 * @throws SQLException if a database error occurs 076 */ 077 private static void displayResultSet(ResultSet resultSet) throws SQLException { 078 ResultSetMetaData metaData = resultSet.getMetaData(); 079 int columnCount = metaData.getColumnCount(); 080 081 // Calculate column widths 082 int[] columnWidths = new int[columnCount]; 083 String[] columnNames = new String[columnCount]; 084 085 for (int i = 1; i <= columnCount; i++) { 086 columnNames[i - 1] = metaData.getColumnLabel(i); 087 columnWidths[i - 1] = Math.max(columnNames[i - 1].length(), 10); 088 } 089 090 // Collect all rows to calculate proper column widths 091 java.util.List<String[]> rows = new java.util.ArrayList<>(); 092 while (resultSet.next()) { 093 String[] row = new String[columnCount]; 094 for (int i = 1; i <= columnCount; i++) { 095 Object value = resultSet.getObject(i); 096 row[i - 1] = value != null ? value.toString() : "NULL"; 097 columnWidths[i - 1] = Math.max(columnWidths[i - 1], row[i - 1].length()); 098 } 099 rows.add(row); 100 } 101 102 // Print header 103 printSeparator(columnWidths); 104 printRow(columnNames, columnWidths); 105 printSeparator(columnWidths); 106 107 // Print data rows 108 if (rows.isEmpty()) { 109 System.out.println("No rows returned"); 110 } else { 111 for (String[] row : rows) { 112 printRow(row, columnWidths); 113 } 114 printSeparator(columnWidths); 115 System.out.println(rows.size() + " row(s) returned"); 116 } 117 } 118 119 /** 120 * Prints a separator line. 121 * 122 * @param columnWidths array of column widths 123 */ 124 private static void printSeparator(int[] columnWidths) { 125 System.out.print("+"); 126 for (int width : columnWidths) { 127 for (int i = 0; i < width + 2; i++) { 128 System.out.print("-"); 129 } 130 System.out.print("+"); 131 } 132 System.out.println(); 133 } 134 135 /** 136 * Prints a data row. 137 * 138 * @param values array of values to print 139 * @param columnWidths array of column widths 140 */ 141 private static void printRow(String[] values, int[] columnWidths) { 142 System.out.print("|"); 143 for (int i = 0; i < values.length; i++) { 144 System.out.print(" "); 145 System.out.print(padRight(values[i], columnWidths[i])); 146 System.out.print(" |"); 147 } 148 System.out.println(); 149 } 150 151 /** 152 * Pads a string to the right with spaces. 153 * 154 * @param str the string to pad 155 * @param length the desired length 156 * @return the padded string 157 */ 158 private static String padRight(String str, int length) { 159 if (str.length() >= length) { 160 return str; 161 } 162 StringBuilder sb = new StringBuilder(str); 163 while (sb.length() < length) { 164 sb.append(' '); 165 } 166 return sb.toString(); 167 } 168}