From 5c97ab69edb44c0f1a7dc416ffaf1b934f7a3d7d Mon Sep 17 00:00:00 2001 From: Chris Jaekl Date: Wed, 22 Jun 2016 21:38:50 +0900 Subject: [PATCH] Add "Describe" command, with support for describing both (a) specific table(s) and for listing all tables. --- src/main/java/net/jaekl/squelch/Squelch.java | 22 +- .../java/net/jaekl/squelch/db/DbDriver.java | 11 + .../jaekl/squelch/db/PostgresqlDriver.java | 5 + src/main/java/net/jaekl/squelch/sql/Row.java | 4 + .../java/net/jaekl/squelch/stmt/Describe.java | 129 +++ .../java/net/jaekl/squelch/stmt/Select.java | 15 +- .../java/net/jaekl/squelch/stmt/Stmt.java | 4 +- .../java/net/jaekl/squelch/stmt/Tabular.java | 13 +- .../jaekl/squelch/stmt/TabularColumnInfo.java | 78 ++ .../java/net/jaekl/squelch/SquelchTest.java | 7 +- .../net/jaekl/squelch/db/DbDriverMock.java | 22 + .../net/jaekl/squelch/sql/ConnectionMock.java | 18 +- .../squelch/sql/DatabaseMetaDataMock.java | 749 +++++++++--------- .../net/jaekl/squelch/sql/ResultSetMock.java | 51 +- .../net/jaekl/squelch/stmt/DescribeTest.java | 270 +++++++ .../net/jaekl/squelch/stmt/TabularTest.java | 2 +- 16 files changed, 1005 insertions(+), 395 deletions(-) create mode 100644 src/main/java/net/jaekl/squelch/stmt/Describe.java create mode 100644 src/main/java/net/jaekl/squelch/stmt/TabularColumnInfo.java create mode 100644 src/test/java/net/jaekl/squelch/db/DbDriverMock.java create mode 100644 src/test/java/net/jaekl/squelch/stmt/DescribeTest.java diff --git a/src/main/java/net/jaekl/squelch/Squelch.java b/src/main/java/net/jaekl/squelch/Squelch.java index 88515e0..848ede7 100644 --- a/src/main/java/net/jaekl/squelch/Squelch.java +++ b/src/main/java/net/jaekl/squelch/Squelch.java @@ -11,6 +11,7 @@ import net.jaekl.squelch.db.MsSqlDriver; import net.jaekl.squelch.db.MySqlDriver; import net.jaekl.squelch.db.OracleDriver; import net.jaekl.squelch.db.PostgresqlDriver; +import net.jaekl.squelch.stmt.Describe; import net.jaekl.squelch.stmt.Select; import net.jaekl.squelch.stmt.Stmt; import net.jaekl.squelch.util.ConsoleInput; @@ -26,6 +27,7 @@ public class Squelch { new PostgresqlDriver() }; private static final Stmt[] READ_ONLY_STATEMENTS = { + new Describe(), new Select() }; @@ -76,11 +78,9 @@ public class Squelch { return false; } - Connection getConnection() throws ClassNotFoundException, SQLException, SquelchException + Connection getConnection(DbDriver driver, String jdbcUrl) + throws ClassNotFoundException, SQLException, SquelchException { - String jdbcUrl = m_args.getUrl(); - DbDriver driver = getDriverFor(jdbcUrl); - return driver.connect(jdbcUrl, m_args.getUser(), m_args.getPass()); } @@ -97,7 +97,10 @@ public class Squelch { void pumpLines(PrintWriter pw, ConsoleInput ci) throws IOException, ClassNotFoundException, SQLException, SquelchException { String line = null; - try (Connection conn = getConnection()) + String jdbcUrl = m_args.getUrl(); + DbDriver driver = getDriverFor(jdbcUrl); + + try (Connection conn = getConnection(driver, jdbcUrl)) { while (true) { boolean processed = false; @@ -105,7 +108,12 @@ public class Squelch { for (Stmt statement : m_statements) { if (statement.handles(line)) { - statement.exec(conn, pw, line); + try { + statement.exec(driver, conn, pw, line); + } + catch (SQLException exc) { + exc.printStackTrace(pw); + } processed = true; break; } @@ -118,8 +126,8 @@ public class Squelch { // Unrecognized command // TODO: add a string table, and a natural-language error message. pw.println("??? \"" + line + "\""); - pw.flush(); } + pw.flush(); } } } diff --git a/src/main/java/net/jaekl/squelch/db/DbDriver.java b/src/main/java/net/jaekl/squelch/db/DbDriver.java index 5e73885..931fcf1 100644 --- a/src/main/java/net/jaekl/squelch/db/DbDriver.java +++ b/src/main/java/net/jaekl/squelch/db/DbDriver.java @@ -3,6 +3,7 @@ package net.jaekl.squelch.db; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; +import java.util.Locale; public abstract class DbDriver { // Returns true iff. this DbDriver knows how to connect to the given JDBC URL @@ -17,4 +18,14 @@ public abstract class DbDriver { Class.forName(getJdbcDriverClassName()); return DriverManager.getConnection(jdbcUrl, userName, password); } + + // If this database uses case-insensitive collation, then return an upper-cased version of the passed string. + // Otherwise (if this database is case-sensitive), return the string unchanged. + // Note that the default implementation assumes a case-insensitive DB. + public String adjustCase(String input) { + if (null == input) { + return ""; // Convert nulls to empty strings, so that we can safely use .equals() on the result + } + return input.toUpperCase(Locale.CANADA); + } } diff --git a/src/main/java/net/jaekl/squelch/db/PostgresqlDriver.java b/src/main/java/net/jaekl/squelch/db/PostgresqlDriver.java index 9020064..97fd12c 100644 --- a/src/main/java/net/jaekl/squelch/db/PostgresqlDriver.java +++ b/src/main/java/net/jaekl/squelch/db/PostgresqlDriver.java @@ -14,4 +14,9 @@ public class PostgresqlDriver extends DbDriver { public String getJdbcDriverClassName() { return "org.postgresql.Driver"; } + + @Override + public String adjustCase(String input) { + return (null == input) ? "" : input; + } } diff --git a/src/main/java/net/jaekl/squelch/sql/Row.java b/src/main/java/net/jaekl/squelch/sql/Row.java index fd47301..88e87e2 100644 --- a/src/main/java/net/jaekl/squelch/sql/Row.java +++ b/src/main/java/net/jaekl/squelch/sql/Row.java @@ -7,6 +7,10 @@ public class Row { m_args = new Object[numCols]; } + public Row(Object[] values) { + m_args = values.clone(); + } + // 1-based index, like JDBC public void setValue(int idx, Object value) { m_args[idx - 1] = value; diff --git a/src/main/java/net/jaekl/squelch/stmt/Describe.java b/src/main/java/net/jaekl/squelch/stmt/Describe.java new file mode 100644 index 0000000..a76e5f0 --- /dev/null +++ b/src/main/java/net/jaekl/squelch/stmt/Describe.java @@ -0,0 +1,129 @@ +package net.jaekl.squelch.stmt; + +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Locale; + +import net.jaekl.squelch.db.DbDriver; + +public class Describe extends Stmt { + + @Override + public boolean handles(String line) + { + if (null == line) { + return false; + } + + String trimmed = line.trim(); + if (trimmed.equals("\\d")) { + return true; + } + if (trimmed.startsWith("\\d ")) { + return true; + } + + String upper = trimmed.toUpperCase(Locale.CANADA); + if (upper.equals("DESCRIBE")) { + return true; + } + if (upper.startsWith("DESCRIBE ")) { + return true; + } + + return false; + } + + @Override + public int exec(DbDriver driver, Connection conn, PrintWriter pw, String line) + throws IOException, SQLException + { + DatabaseMetaData metaData = conn.getMetaData(); + + String trimmed = line.trim(); + String tablePattern; + if (trimmed.startsWith("\\d")) { + tablePattern = trimmed.substring(2).trim(); + } + else { + assert (trimmed.toUpperCase(Locale.CANADA).startsWith("DESCRIBE")); + tablePattern = trimmed.substring(8).trim(); + } + tablePattern = driver.adjustCase(tablePattern); + + if (tablePattern.length() < 1) { + return describeAll(pw, metaData); + } + else { + return describeTable(pw, metaData, tablePattern); + } + } + + int describeAll(PrintWriter pw, DatabaseMetaData metaData) + throws SQLException + { + try (ResultSet rs = metaData.getTables(null, null, "%", null)) + { + TabularResultSet tabular = new TabularResultSet(rs); + // TODO: StringTable i18n + tabular.printTable(pw, "???"); + } + + return 0; + } + + int describeTable(PrintWriter pw, DatabaseMetaData metaData, String tablePattern) + throws SQLException + { + boolean found = false; + String trimmed = tablePattern.trim(); + + try (ResultSet rs = metaData.getTables(null, null, trimmed, null)) + { + while (rs.next()) { + found = true; + describe(pw, metaData, rs); + } + } + + if (!found) { + // TODO: StringTable i18n + pw.println("??? " + trimmed); + } + return 0; + } + + void describe(PrintWriter pw, DatabaseMetaData metaData, ResultSet tableRs) + throws SQLException + { + String catalogueName = tableRs.getString(1); + String schemaName = tableRs.getString(2); + String tableName = tableRs.getString(3); + String tableType = tableRs.getString(4); + String remarks = tableRs.getString(5); + + pw.print("" + tableType + " "); + if (null != catalogueName) { + pw.print(catalogueName + "."); + } + if (null != schemaName) { + pw.print(schemaName + "."); + } + pw.print("" + tableName); + if ((null != remarks) && (remarks.length() > 0)) { + pw.print(" (" + remarks + ")"); + } + pw.println(""); + + try (ResultSet colsRs = metaData.getColumns(catalogueName, schemaName, tableName, null)) + { + TabularColumnInfo tabular = new TabularColumnInfo(colsRs); + // TODO: StringTable i18n + tabular.printTable(pw, "???"); + } + } +} diff --git a/src/main/java/net/jaekl/squelch/stmt/Select.java b/src/main/java/net/jaekl/squelch/stmt/Select.java index f34b8c9..c5f785e 100644 --- a/src/main/java/net/jaekl/squelch/stmt/Select.java +++ b/src/main/java/net/jaekl/squelch/stmt/Select.java @@ -8,6 +8,8 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Locale; +import net.jaekl.squelch.db.DbDriver; + public class Select extends Query { @Override @@ -21,11 +23,17 @@ public class Select extends Query { } @Override - public int exec(Connection conn, PrintWriter pw, String line) throws IOException, SQLException + public int exec(DbDriver driver, Connection conn, PrintWriter pw, String line) throws IOException, SQLException { int rowCount = 0; - try (PreparedStatement ps = conn.prepareStatement(line)) + // If there's a ';' on the end of this line, remove it. + String trimmed = line.trim(); + if (trimmed.endsWith(";")) { + trimmed = trimmed.substring(0, trimmed.length() - 1); + } + + try (PreparedStatement ps = conn.prepareStatement(trimmed)) { try (ResultSet rs = ps.executeQuery()) { @@ -38,7 +46,8 @@ public class Select extends Query { private int printFormatted(PrintWriter pw, ResultSet rs) throws IOException, SQLException { TabularResultSet trs = new TabularResultSet(rs); - int rowCount = trs.printTable(pw); + // TODO: StringTable i18n + int rowCount = trs.printTable(pw, "No rows returned."); pw.flush(); return rowCount; diff --git a/src/main/java/net/jaekl/squelch/stmt/Stmt.java b/src/main/java/net/jaekl/squelch/stmt/Stmt.java index fc090d4..893cfdd 100644 --- a/src/main/java/net/jaekl/squelch/stmt/Stmt.java +++ b/src/main/java/net/jaekl/squelch/stmt/Stmt.java @@ -5,6 +5,8 @@ import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; +import net.jaekl.squelch.db.DbDriver; + /** * Abstract base class for all statements (e.g., Insert, Create, Delete, Describe) */ @@ -14,5 +16,5 @@ public abstract class Stmt { abstract public boolean handles(String line); // Execute line as a statement of this type - abstract public int exec(Connection conn, PrintWriter pw, String line) throws IOException, SQLException; + abstract public int exec(DbDriver driver, Connection conn, PrintWriter pw, String line) throws IOException, SQLException; } diff --git a/src/main/java/net/jaekl/squelch/stmt/Tabular.java b/src/main/java/net/jaekl/squelch/stmt/Tabular.java index af3d5da..130f4a5 100644 --- a/src/main/java/net/jaekl/squelch/stmt/Tabular.java +++ b/src/main/java/net/jaekl/squelch/stmt/Tabular.java @@ -41,7 +41,9 @@ abstract public class Tabular { abstract Row getNext() throws SQLException; // Returns the number of (data) rows that were output - public int printTable(PrintWriter pw) throws SQLException { + public int printTable(PrintWriter pw, String noRowsMessage) + throws SQLException + { int rowCount = 0; Column[] cols = getCols(); RowBuffer rowBuf; @@ -68,10 +70,13 @@ abstract public class Tabular { if (rowCount > 0) { writeDivider(pw, colWidths); + // TODO: Implement a String table for i18n + pw.println("" + rowCount + " row(s) returned."); + } + else { + pw.println(noRowsMessage); } - // TODO: Implement a String table for i18n - pw.println("" + rowCount + " row(s) returned."); pw.flush(); return rowCount; @@ -206,7 +211,7 @@ abstract public class Tabular { } return Object.class; } - + String repChar(char chr, int times) { StringBuffer sb = new StringBuffer(); diff --git a/src/main/java/net/jaekl/squelch/stmt/TabularColumnInfo.java b/src/main/java/net/jaekl/squelch/stmt/TabularColumnInfo.java new file mode 100644 index 0000000..ff9fc62 --- /dev/null +++ b/src/main/java/net/jaekl/squelch/stmt/TabularColumnInfo.java @@ -0,0 +1,78 @@ +package net.jaekl.squelch.stmt; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import net.jaekl.squelch.sql.Column; +import net.jaekl.squelch.sql.Row; + +public class TabularColumnInfo extends Tabular { + private static final Column[] COLUMNS = { + new Column("Column", String.class, 32), + new Column("Type", String.class, 16), + new Column("Modifiers", String.class, 16) + }; + private ResultSet m_rs; + + public TabularColumnInfo(ResultSet rs) { + m_rs = rs; + } + + @Override + Column[] getCols() throws SQLException { + return COLUMNS; + } + + @Override + Row getNext() throws SQLException { + if (!m_rs.next()) { + return null; + } + + Row row = new Row(COLUMNS.length); + + String columnName = m_rs.getString(4); + + String typeName = m_rs.getString(6); + int columnSize = m_rs.getInt(7); + if (columnSize > 0) { + int decimalDigits = m_rs.getInt(8); // digits after the decimal point + if (decimalDigits > 0) { + typeName += "(" + columnSize + "." + decimalDigits + ")"; + } + else { + typeName += "(" + columnSize + ")"; + } + } + + String remarks = m_rs.getString(12); + String isNullable = m_rs.getString(18); + String isAutoIncrement = m_rs.getString(23); + String notes = ""; + if ("YES".equals(isNullable)) { + notes += "NULL"; + } + else if ("NO".equals(isNullable)) { + notes += "NOT NULL"; + } + if ("YES".equals(isAutoIncrement)) { + if (notes.length() > 0) { + notes += " "; + } + notes += "AUTOINCREMENT"; + } + if ((null != remarks) && (remarks.length() > 0)) { + if (notes.length() > 0) { + notes += " "; + } + notes += "(" + remarks + ")"; + } + + row.setValue(1, columnName); + row.setValue(2, typeName); + row.setValue(3, notes); + + return row; + } + +} diff --git a/src/test/java/net/jaekl/squelch/SquelchTest.java b/src/test/java/net/jaekl/squelch/SquelchTest.java index be533d8..44b7de9 100644 --- a/src/test/java/net/jaekl/squelch/SquelchTest.java +++ b/src/test/java/net/jaekl/squelch/SquelchTest.java @@ -32,7 +32,8 @@ public class SquelchTest { } @Override - Connection getConnection() throws ClassNotFoundException, SQLException, SquelchException + Connection getConnection(DbDriver driver, String jdbcUrl) + throws ClassNotFoundException, SQLException, SquelchException { return m_conn; } @@ -140,11 +141,11 @@ public class SquelchTest { String[] simpleSelect = { "SELECT * FROM Fred WHERE wife='Wilma';", "QUIT" }; consoleOutput = runPump(squelch, simpleSelect); assertEquals( Squelch.PROMPT + simpleSelect[0] + "\n" - + "0 row(s) returned.\n" + + "No rows returned.\n" + Squelch.PROMPT + simpleSelect[1] + "\n", consoleOutput); ConnectionMock cm = squelch.mock_getConnectionMock(); - assertTrue(cm.mock_queryWasExecuted(simpleSelect[0])); + assertTrue(cm.mock_queryWasExecuted(simpleSelect[0].substring(0, simpleSelect[0].length() - 1))); } private String runPump(Squelch squelch, String[] lines) throws IOException, ClassNotFoundException, SQLException, SquelchException diff --git a/src/test/java/net/jaekl/squelch/db/DbDriverMock.java b/src/test/java/net/jaekl/squelch/db/DbDriverMock.java new file mode 100644 index 0000000..1434d8a --- /dev/null +++ b/src/test/java/net/jaekl/squelch/db/DbDriverMock.java @@ -0,0 +1,22 @@ +package net.jaekl.squelch.db; + +public class DbDriverMock extends DbDriver { + + @Override + public boolean handles(String jdbcUrl) { + return true; + } + + @Override + String getJdbcDriverClassName() { + return getClass().getCanonicalName(); + } + + @Override + public String adjustCase(String input) { + if (null == input) { + return ""; // Convert nulls to empty strings, so that we can safely use .equals() on the result + } + return input; + } +} diff --git a/src/test/java/net/jaekl/squelch/sql/ConnectionMock.java b/src/test/java/net/jaekl/squelch/sql/ConnectionMock.java index 22b686f..40e6229 100644 --- a/src/test/java/net/jaekl/squelch/sql/ConnectionMock.java +++ b/src/test/java/net/jaekl/squelch/sql/ConnectionMock.java @@ -22,22 +22,29 @@ import java.util.concurrent.Executor; public class ConnectionMock implements Connection { - private ArrayList m_executedQueries; + private ArrayList mock_executedQueries; + private DatabaseMetaDataMock mock_databaseMetaData; public ConnectionMock() { - m_executedQueries = new ArrayList(); + mock_executedQueries = new ArrayList(); + mock_databaseMetaData = new DatabaseMetaDataMock(); } public ResultSetMock mock_executeQuery(PreparedStatementMock psm) { - m_executedQueries.add(psm.toString()); + mock_executedQueries.add(psm.toString()); return new ResultSetMock(); } public boolean mock_queryWasExecuted(String sql) { // There's an assumption here that we don't try a large number of queries in a single test. // If that assumption is false, then we should change this to be more efficient. - return m_executedQueries.contains(sql); + return mock_executedQueries.contains(sql); + } + + public void mock_setDatabaseMetaData(DatabaseMetaDataMock dbmdm) + { + mock_databaseMetaData = dbmdm; } @Override @@ -167,8 +174,7 @@ public class ConnectionMock implements Connection { @Override public DatabaseMetaData getMetaData() throws SQLException { - DatabaseMetaData result = new DatabaseMetaDataMock(); - return result; + return mock_databaseMetaData; } @Override diff --git a/src/test/java/net/jaekl/squelch/sql/DatabaseMetaDataMock.java b/src/test/java/net/jaekl/squelch/sql/DatabaseMetaDataMock.java index b8ecded..7b12a80 100644 --- a/src/test/java/net/jaekl/squelch/sql/DatabaseMetaDataMock.java +++ b/src/test/java/net/jaekl/squelch/sql/DatabaseMetaDataMock.java @@ -5,1098 +5,1139 @@ import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.RowIdLifetime; import java.sql.SQLException; +import java.util.HashMap; public class DatabaseMetaDataMock implements DatabaseMetaData { + private HashMap mock_colMap; + private HashMap mock_tableMap; + + public DatabaseMetaDataMock() { + mock_colMap = new HashMap(); + mock_tableMap = new HashMap(); + } + + private String mock_colRSKey(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) { + return "" + catalog + ":" + schemaPattern + ":" + tableNamePattern + ":" + columnNamePattern; + } + + public void mock_setColRS(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern, ResultSetMock value) { + String key = mock_colRSKey(catalog, schemaPattern, tableNamePattern, columnNamePattern); + mock_colMap.put(key, value); + } + + public void mock_setTableRS(String catalog, String schemaPattern, String tableNamePattern, String[] types, ResultSetMock value) { + String key = mock_tableKey(catalog, schemaPattern, tableNamePattern, types); + mock_tableMap.put(key, value); + } + private String mock_tableKey(String catalog, String schemaPattern, String tableNamePattern, String[] types) { + StringBuilder sb = new StringBuilder(); + sb.append("" + catalog + ":" + schemaPattern + ":" + tableNamePattern); + if (null != types) { + for (String s : types) { + sb.append(":" + s); + } + } + return sb.toString(); + } + @Override public boolean isWrapperFor(Class iface) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public T unwrap(Class iface) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean allProceduresAreCallable() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean allTablesAreSelectable() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean autoCommitFailureClosesAllResultSets() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean dataDefinitionCausesTransactionCommit() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean dataDefinitionIgnoredInTransactions() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean deletesAreDetected(int type) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean generatedKeyAlwaysReturned() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getCatalogSeparator() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getCatalogTerm() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getCatalogs() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getClientInfoProperties() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override - public ResultSet getColumns(String catalog, String schemaPattern, - String tableNamePattern, String columnNamePattern) - throws SQLException { - // TODO Auto-generated method stub - return null; + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) + throws SQLException + { + String key = mock_colRSKey(catalog, schemaPattern, tableNamePattern, columnNamePattern); + ResultSetMock rsm = mock_colMap.get(key); + if (null == rsm) { + rsm = new ResultSetMock(); + } + return rsm; } @Override public Connection getConnection() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getDatabaseMajorVersion() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getDatabaseMinorVersion() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getDatabaseProductName() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getDatabaseProductVersion() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getDefaultTransactionIsolation() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getDriverMajorVersion() { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getDriverMinorVersion() { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getDriverName() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getDriverVersion() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getExtraNameCharacters() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getIdentifierQuoteString() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getJDBCMajorVersion() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getJDBCMinorVersion() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxBinaryLiteralLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxCatalogNameLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxCharLiteralLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxColumnNameLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxColumnsInGroupBy() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxColumnsInIndex() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxColumnsInOrderBy() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxColumnsInSelect() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxColumnsInTable() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxConnections() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxCursorNameLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxIndexLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxProcedureNameLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxRowSize() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxSchemaNameLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxStatementLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxStatements() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxTableNameLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxTablesInSelect() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getMaxUserNameLength() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getNumericFunctions() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getProcedureTerm() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getResultSetHoldability() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public RowIdLifetime getRowIdLifetime() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getSQLKeywords() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public int getSQLStateType() throws SQLException { - // TODO Auto-generated method stub - return 0; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getSchemaTerm() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getSchemas() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getSearchStringEscape() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getStringFunctions() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getSystemFunctions() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getTableTypes() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException { - ResultSetMock result = new ResultSetMock(); + String key = mock_tableKey(catalog, schemaPattern, tableNamePattern, types); + ResultSetMock result = mock_tableMap.get(key); + if (null == result) { + result = new ResultSetMock(); + } return result; } @Override public String getTimeDateFunctions() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getTypeInfo() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getURL() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public String getUserName() throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { - // TODO Auto-generated method stub - return null; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean insertsAreDetected(int type) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean isCatalogAtStart() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean isReadOnly() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean locatorsUpdateCopy() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean nullPlusNonNullIsNull() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean nullsAreSortedAtEnd() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean nullsAreSortedAtStart() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean nullsAreSortedHigh() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean nullsAreSortedLow() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean othersDeletesAreVisible(int type) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean othersInsertsAreVisible(int type) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean othersUpdatesAreVisible(int type) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean ownDeletesAreVisible(int type) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean ownInsertsAreVisible(int type) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean ownUpdatesAreVisible(int type) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean storesLowerCaseIdentifiers() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean storesMixedCaseIdentifiers() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean storesUpperCaseIdentifiers() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsANSI92EntryLevelSQL() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsANSI92FullSQL() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsANSI92IntermediateSQL() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsAlterTableWithAddColumn() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsAlterTableWithDropColumn() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsBatchUpdates() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsCatalogsInDataManipulation() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsCatalogsInIndexDefinitions() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsCatalogsInProcedureCalls() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsCatalogsInTableDefinitions() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsColumnAliasing() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsConvert() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsConvert(int fromType, int toType) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsCoreSQLGrammar() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsCorrelatedSubqueries() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsDataManipulationTransactionsOnly() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsDifferentTableCorrelationNames() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsExpressionsInOrderBy() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsExtendedSQLGrammar() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsFullOuterJoins() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsGetGeneratedKeys() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsGroupBy() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsGroupByBeyondSelect() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsGroupByUnrelated() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsIntegrityEnhancementFacility() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsLikeEscapeClause() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsLimitedOuterJoins() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsMinimumSQLGrammar() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsMixedCaseIdentifiers() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsMultipleOpenResults() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsMultipleResultSets() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsMultipleTransactions() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsNamedParameters() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsNonNullableColumns() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsOpenCursorsAcrossCommit() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsOpenCursorsAcrossRollback() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsOpenStatementsAcrossCommit() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsOpenStatementsAcrossRollback() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsOrderByUnrelated() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsOuterJoins() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsPositionedDelete() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsPositionedUpdate() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsResultSetHoldability(int holdability) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsResultSetType(int type) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSavepoints() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSchemasInDataManipulation() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSchemasInIndexDefinitions() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSchemasInProcedureCalls() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSchemasInTableDefinitions() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSelectForUpdate() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsStatementPooling() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsStoredProcedures() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSubqueriesInComparisons() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSubqueriesInExists() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSubqueriesInIns() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsSubqueriesInQuantifieds() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsTableCorrelationNames() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsTransactionIsolationLevel(int level) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsTransactions() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsUnion() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean supportsUnionAll() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean updatesAreDetected(int type) throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean usesLocalFilePerTable() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } @Override public boolean usesLocalFiles() throws SQLException { - // TODO Auto-generated method stub - return false; + throw new UnsupportedOperationException("Not yet implemented"); + } } diff --git a/src/test/java/net/jaekl/squelch/sql/ResultSetMock.java b/src/test/java/net/jaekl/squelch/sql/ResultSetMock.java index b398e24..a2f8a99 100644 --- a/src/test/java/net/jaekl/squelch/sql/ResultSetMock.java +++ b/src/test/java/net/jaekl/squelch/sql/ResultSetMock.java @@ -25,18 +25,24 @@ import java.util.Map; public class ResultSetMock implements ResultSet { - private ResultSetMetaDataMock m_metaDataMock; - private ArrayList m_rows; - private int m_rowNum; + private ResultSetMetaDataMock mock_metaDataMock; + private ArrayList mock_rows; + private int mock_rowIdx; public ResultSetMock() { - m_metaDataMock = new ResultSetMetaDataMock(); - m_rows = new ArrayList(); - m_rowNum = -1; + mock_metaDataMock = new ResultSetMetaDataMock(); + mock_rows = new ArrayList(); + mock_rowIdx = -1; } public void mock_addRow(Row row) { - m_rows.add(row); + mock_rows.add(row); + } + + public void mock_addRows(Row[] rows) { + for (Row row : rows) { + mock_addRow(row); + } } @Override @@ -317,9 +323,17 @@ public class ResultSetMock implements ResultSet { } @Override - public int getInt(int arg0) throws SQLException { - throw new UnsupportedOperationException("Not yet implemented."); - + public int getInt(int idx) throws SQLException { + Row row = mock_rows.get(mock_rowIdx); + Object obj = row.getValue(idx); + if (null == obj) { + return 0; + } + if (obj instanceof Number) { + Number num = (Number)obj; + return num.intValue(); + } + throw new SQLException("Invalid type"); } @Override @@ -330,7 +344,7 @@ public class ResultSetMock implements ResultSet { @Override public long getLong(int idx) throws SQLException { - Row row = m_rows.get(m_rowNum); + Row row = mock_rows.get(mock_rowIdx); return (Long)(row.getValue(idx)); } @@ -342,7 +356,7 @@ public class ResultSetMock implements ResultSet { @Override public ResultSetMetaData getMetaData() throws SQLException { - return m_metaDataMock; + return mock_metaDataMock; } @Override @@ -383,7 +397,7 @@ public class ResultSetMock implements ResultSet { @Override public Object getObject(int idx) throws SQLException { - Row row = m_rows.get(m_rowNum); + Row row = mock_rows.get(mock_rowIdx); return row.getValue(idx); } @@ -481,7 +495,7 @@ public class ResultSetMock implements ResultSet { @Override public String getString(int idx) throws SQLException { - Row row = m_rows.get(m_rowNum); + Row row = mock_rows.get(mock_rowIdx); return (String)(row.getValue(idx)); } @@ -493,7 +507,7 @@ public class ResultSetMock implements ResultSet { @Override public Time getTime(int idx) throws SQLException { - Row row = m_rows.get(m_rowNum); + Row row = mock_rows.get(mock_rowIdx); return new Time(((java.util.Date)row.getValue(idx)).getTime()); } @@ -634,7 +648,12 @@ public class ResultSetMock implements ResultSet { @Override public boolean next() throws SQLException { - return false; + if (null == mock_rows) { + return false; + } + + mock_rowIdx++; + return (mock_rowIdx < mock_rows.size()); } @Override diff --git a/src/test/java/net/jaekl/squelch/stmt/DescribeTest.java b/src/test/java/net/jaekl/squelch/stmt/DescribeTest.java new file mode 100644 index 0000000..f211105 --- /dev/null +++ b/src/test/java/net/jaekl/squelch/stmt/DescribeTest.java @@ -0,0 +1,270 @@ +package net.jaekl.squelch.stmt; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +import net.jaekl.squelch.db.DbDriverMock; +import net.jaekl.squelch.sql.ConnectionMock; +import net.jaekl.squelch.sql.DatabaseMetaDataMock; +import net.jaekl.squelch.sql.ResultSetMock; +import net.jaekl.squelch.sql.Row; + +import org.junit.Test; + +public class DescribeTest { + + @Test + public void testHandles() { + final String[] AFFIRMATIVE = { + "\\d", "\\d ", " \\d", " \\d ", + "describe", "describe ", " describe", " describe ", + "DESCRIBE", "DESCRIBE ", " DESCRIBE", " DESCRIBE ", + "descRIbe", "DEscribE ", " DEScribe", " DEscRIbE ", + "\\d tablename", "\\d tablename ", " \\d tablename", " \\d tableName ", + "describe tablename", "DESCRIBE tablename ", " DesCrIbE tablename", " DESCribE fred " + }; + final String[] NEGATIVE = { + "\\d\\q", "", null, " ", "select * from foo", " select * from foo ", + "DESCRIBEQ", "describeFOO", " describeJackAndDianne " + }; + + Describe describe = new Describe(); + for (String s : AFFIRMATIVE) { + assertTrue("handles " + s, describe.handles(s)); + } + for (String s : NEGATIVE) { + assertFalse("does not handle " + s, describe.handles(s)); + } + } + + @Test + public void testDescribeAll_noTables() throws IOException, SQLException + { + DatabaseMetaDataMock dbmdm = new DatabaseMetaDataMock(); + Describe describe = new Describe(); + + try ( + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8)); + ) + { + describe.describeAll(pw, dbmdm); + pw.close(); + baos.close(); + String actual = baos.toString(); + final String EXPECTED = "???\n"; + assertEquals(EXPECTED, actual); + } + } + + @Test + public void testDescribeTable_noColumns() + throws IOException, SQLException + { + DatabaseMetaDataMock dbmdm = new DatabaseMetaDataMock(); + Describe describe = new Describe(); + + try ( + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8)); + ) + { + describe.describeTable(pw, dbmdm, "%"); + pw.close(); + baos.close(); + String actual = baos.toString(); + final String EXPECTED = "??? %\n"; + assertEquals(EXPECTED, actual); + } + } + + private DatabaseMetaDataMock construct_runs_dbmdm() + { + ResultSetMock rsmCols = new ResultSetMock(); + ResultSetMock rsmTables = new ResultSetMock(); + + DatabaseMetaDataMock dbmdm = new DatabaseMetaDataMock(); + Row[] rows = { + new Row(new Object[]{ + null, // 1) table_cat + "public", // 2) table schema + "runs", // 3) table name + "runid", // 4) column name + Integer.valueOf(4), // 5) data type + "int4", // 6) type name + Integer.valueOf(10), // 7) column size + null, // 8) buffer length + null, // 9) decimal digits + Integer.valueOf(10), // 10) num_prec_radix + Integer.valueOf(DatabaseMetaData.columnNoNulls), // 11) nullable + null, // 12) remarks + null, // 13) default value for the column + Integer.valueOf(0), // 14) sql_data_type + Integer.valueOf(0), // 15) sql_datetime_sub + null, // 16) char_octet_length + Integer.valueOf(1), // 17) ordinal_position + "NO", // 18) is_nullable + null, // 19) scope_catalog + null, // 20) scope_schema + null, // 21) scope_table + null, // 22) source_data_type + "NO", // 23) is_autoincrement + "NO" // 24) is_generated_column + }), + new Row(new Object[]{ + null, // 1) table_cat + "public", // 2) table schema + "runs", // 3) table name + "projname", // 4) column name + Integer.valueOf(12), // 5) data type + "varchar", // 6) type name + Integer.valueOf(80), // 7) column size + null, // 8) buffer length + null, // 9) decimal digits + Integer.valueOf(10), // 10) num_prec_radix + Integer.valueOf(DatabaseMetaData.columnNoNulls), // 11) nullable + null, // 12) remarks + null, // 13) default value for the column + Integer.valueOf(0), // 14) sql_data_type + Integer.valueOf(0), // 15) sql_datetime_sub + null, // 16) char_octet_length + Integer.valueOf(2), // 17) ordinal_position + "NO", // 18) is_nullable + null, // 19) scope_catalog + null, // 20) scope_schema + null, // 21) scope_table + null, // 22) source_data_type + "NO", // 23) is_autoincrement + "NO" // 24) is_generated_column + }), + new Row(new Object[]{ + null, // 1) table_cat + "public", // 2) table schema + "runs", // 3) table name + "version", // 4) column name + Integer.valueOf(12), // 5) data type + "varchar", // 6) type name + Integer.valueOf(10), // 7) column size + null, // 8) buffer length + null, // 9) decimal digits + Integer.valueOf(10), // 10) num_prec_radix + Integer.valueOf(DatabaseMetaData.columnNullable), // 11) nullable + null, // 12) remarks + null, // 13) default value for the column + Integer.valueOf(0), // 14) sql_data_type + Integer.valueOf(0), // 15) sql_datetime_sub + null, // 16) char_octet_length + Integer.valueOf(1), // 17) ordinal_position + "YES", // 18) is_nullable + null, // 19) scope_catalog + null, // 20) scope_schema + null, // 21) scope_table + null, // 22) source_data_type + "NO", // 23) is_autoincrement + "NO" // 24) is_generated_column + }) + }; + rsmCols.mock_addRows(rows); + + rows = new Row[] { + new Row(new Object[]{ + null, // TABLE_CAT String => table catalog (may be null) + null, // TABLE_SCHEM String => table schema (may be null) + "runs", // TABLE_NAME String => table name + "TABLE", // TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM". + "", // REMARKS String => explanatory comment on the table + null, // TYPE_CAT String => the types catalog (may be null) + null, // TYPE_SCHEM String => the types schema (may be null) + null, // TYPE_NAME String => type name (may be null) + null, // SELF_REFERENCING_COL_NAME String => name of the designated "identifier" column of a typed table (may be null) + null // REF_GENERATION String => specifies how values in SELF_REFERENCING_COL_NAME are created. Values are "SYSTEM", "USER", "DERIVED". (may be null) + }) + }; + rsmTables.mock_addRows(rows); + + dbmdm.mock_setColRS(null, null, "runs", null, rsmCols); + dbmdm.mock_setTableRS(null, null, "runs", null, rsmTables); + + return dbmdm; + } + + private String construct_runs_expected() { + return "TABLE runs\n" + + "+--------+-----------+---------+\n" + + "| Column | Type |Modifiers|\n" + + "+--------+-----------+---------+\n" + + "|runid |int4(10) |NOT NULL |\n" + + "|projname|varchar(80)|NOT NULL |\n" + + "|version |varchar(10)|NULL |\n" + + "+--------+-----------+---------+\n" + + "3 row(s) returned.\n"; + } + + @Test + public void testDescribeTable_threeColumns() + throws IOException, SQLException + { + DatabaseMetaDataMock dbmdm = construct_runs_dbmdm(); + Describe describe = new Describe(); + + try ( + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8)); + ) + { + describe.describeTable(pw, dbmdm, "runs"); + pw.close(); + baos.close(); + String actual = baos.toString(); + String expected = construct_runs_expected(); + + assertEquals(expected, actual); + } + } + + @Test + public void testExec() throws IOException, SQLException + { + final String[] SUCCESSFUL = { + "\\d runs", " \\d runs", "\\d runs ", " \\d runs ", + "DESCRIBE runs", " DescRIBe runs", "describe runs ", " describe runs " + }; + String expected = construct_runs_expected(); + for (String stmt : SUCCESSFUL) { + String actual = doExec(stmt); + assertEquals("doExec(): " + stmt, expected, actual); + } + } + + public String doExec(String stmt) throws IOException, SQLException + { + DatabaseMetaDataMock dbmdm = construct_runs_dbmdm(); + DbDriverMock driver = new DbDriverMock(); + ConnectionMock cm = new ConnectionMock(); + cm.mock_setDatabaseMetaData(dbmdm); + + Describe describe = new Describe(); + + try ( + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8)); + ) + { + describe.exec(driver, cm, pw, stmt); + pw.close(); + baos.close(); + String actual = baos.toString(); + + return actual; + } + } +} diff --git a/src/test/java/net/jaekl/squelch/stmt/TabularTest.java b/src/test/java/net/jaekl/squelch/stmt/TabularTest.java index f6749f2..f0e05bf 100644 --- a/src/test/java/net/jaekl/squelch/stmt/TabularTest.java +++ b/src/test/java/net/jaekl/squelch/stmt/TabularTest.java @@ -106,7 +106,7 @@ public class TabularTest { PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8)); ) { - tabular.printTable(pw); + tabular.printTable(pw, "No rows returned."); pw.close(); baos.close(); String actual = baos.toString(); -- 2.30.2