diff --git a/lib/src/main/java/com/wherobots/db/jdbc/WherobotsDatabaseMetaData.java b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsDatabaseMetaData.java new file mode 100644 index 0000000..c1218ae --- /dev/null +++ b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsDatabaseMetaData.java @@ -0,0 +1,900 @@ +package com.wherobots.db.jdbc; + +import com.wherobots.db.jdbc.session.WherobotsSession; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.RowIdLifetime; +import java.sql.SQLException; + +public class WherobotsDatabaseMetaData implements DatabaseMetaData { + + private final WherobotsJdbcConnection connection; + private final WherobotsSession session; + + public WherobotsDatabaseMetaData(WherobotsJdbcConnection connection, WherobotsSession session) { + this.connection = connection; + this.session = session; + } + + @Override + public boolean allProceduresAreCallable() throws SQLException { + return false; + } + + @Override + public boolean allTablesAreSelectable() throws SQLException { + return true; + } + + @Override + public String getURL() throws SQLException { + return this.session.getURI().toString(); + } + + @Override + public String getUserName() throws SQLException { + return ""; + } + + @Override + public boolean isReadOnly() throws SQLException { + return this.connection.isReadOnly(); + } + + @Override + public boolean nullsAreSortedHigh() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedLow() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedAtEnd() throws SQLException { + return false; + } + + @Override + public String getDatabaseProductName() throws SQLException { + return WherobotsJdbcDriver.DRIVER_NAME; + } + + @Override + public String getDatabaseProductVersion() throws SQLException { + return "latest"; + } + + @Override + public String getDriverName() throws SQLException { + return WherobotsJdbcDriver.DRIVER_NAME; + } + + @Override + public String getDriverVersion() throws SQLException { + return String.format("%d.%d", WherobotsJdbcDriver.MAJOR_VERSION, WherobotsJdbcDriver.MINOR_VERSION); + } + + @Override + public int getDriverMajorVersion() { + return WherobotsJdbcDriver.MAJOR_VERSION; + } + + @Override + public int getDriverMinorVersion() { + return WherobotsJdbcDriver.MINOR_VERSION; + } + + @Override + public boolean usesLocalFiles() throws SQLException { + return false; + } + + @Override + public boolean usesLocalFilePerTable() throws SQLException { + return false; + } + + @Override + public boolean supportsMixedCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesUpperCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesLowerCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesMixedCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public String getIdentifierQuoteString() throws SQLException { + return "\""; + } + + @Override + public String getSQLKeywords() throws SQLException { + return ""; + } + + @Override + public String getNumericFunctions() throws SQLException { + return ""; + } + + @Override + public String getStringFunctions() throws SQLException { + return ""; + } + + @Override + public String getSystemFunctions() throws SQLException { + return ""; + } + + @Override + public String getTimeDateFunctions() throws SQLException { + return ""; + } + + @Override + public String getSearchStringEscape() throws SQLException { + return ""; + } + + @Override + public String getExtraNameCharacters() throws SQLException { + return ""; + } + + @Override + public boolean supportsAlterTableWithAddColumn() throws SQLException { + return false; + } + + @Override + public boolean supportsAlterTableWithDropColumn() throws SQLException { + return false; + } + + @Override + public boolean supportsColumnAliasing() throws SQLException { + return true; + } + + @Override + public boolean nullPlusNonNullIsNull() throws SQLException { + return false; + } + + @Override + public boolean supportsConvert() throws SQLException { + return false; + } + + @Override + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + @Override + public boolean supportsTableCorrelationNames() throws SQLException { + return false; + } + + @Override + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return false; + } + + @Override + public boolean supportsExpressionsInOrderBy() throws SQLException { + return false; + } + + @Override + public boolean supportsOrderByUnrelated() throws SQLException { + return false; + } + + @Override + public boolean supportsGroupBy() throws SQLException { + return true; + } + + @Override + public boolean supportsGroupByUnrelated() throws SQLException { + return true; + } + + @Override + public boolean supportsGroupByBeyondSelect() throws SQLException { + return true; + } + + @Override + public boolean supportsLikeEscapeClause() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsNonNullableColumns() throws SQLException { + return true; + } + + @Override + public boolean supportsMinimumSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsCoreSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsExtendedSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } + + @Override + public boolean supportsOuterJoins() throws SQLException { + return true; + } + + @Override + public boolean supportsFullOuterJoins() throws SQLException { + return true; + } + + @Override + public boolean supportsLimitedOuterJoins() throws SQLException { + return true; + } + + @Override + public String getSchemaTerm() throws SQLException { + return ""; + } + + @Override + public String getProcedureTerm() throws SQLException { + return ""; + } + + @Override + public String getCatalogTerm() throws SQLException { + return ""; + } + + @Override + public boolean isCatalogAtStart() throws SQLException { + return true; + } + + @Override + public String getCatalogSeparator() throws SQLException { + return "."; + } + + @Override + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return true; + } + + @Override + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return true; + } + + @Override + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsPositionedDelete() throws SQLException { + return false; + } + + @Override + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + @Override + public boolean supportsSelectForUpdate() throws SQLException { + return false; + } + + @Override + public boolean supportsStoredProcedures() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInComparisons() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInExists() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInIns() throws SQLException { + return true; + } + + @Override + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return false; + } + + @Override + public boolean supportsCorrelatedSubqueries() throws SQLException { + return false; + } + + @Override + public boolean supportsUnion() throws SQLException { + return false; + } + + @Override + public boolean supportsUnionAll() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return false; + } + + @Override + public int getMaxBinaryLiteralLength() throws SQLException { + return 0; + } + + @Override + public int getMaxCharLiteralLength() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInGroupBy() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInIndex() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInOrderBy() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInSelect() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInTable() throws SQLException { + return 0; + } + + @Override + public int getMaxConnections() throws SQLException { + return 1; + } + + @Override + public int getMaxCursorNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxIndexLength() throws SQLException { + return 0; + } + + @Override + public int getMaxSchemaNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxProcedureNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxCatalogNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxRowSize() throws SQLException { + return 0; + } + + @Override + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } + + @Override + public int getMaxStatementLength() throws SQLException { + return 0; + } + + @Override + public int getMaxStatements() throws SQLException { + return 0; + } + + @Override + public int getMaxTableNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxTablesInSelect() throws SQLException { + return 0; + } + + @Override + public int getMaxUserNameLength() throws SQLException { + return 0; + } + + @Override + public int getDefaultTransactionIsolation() throws SQLException { + return 0; + } + + @Override + public boolean supportsTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + return false; + } + + @Override + public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + return false; + } + + @Override + public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + return false; + } + + @Override + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return false; + } + + @Override + public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException { + return null; + } + + @Override + public ResultSet getSchemas() throws SQLException { + return this.connection.createStatement().executeQuery("SHOW SCHEMAS"); + } + + @Override + public ResultSet getCatalogs() throws SQLException { + return this.connection.createStatement().executeQuery("SHOW CATALOGS"); + } + + @Override + public ResultSet getTableTypes() throws SQLException { + return null; + } + + @Override + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { + return null; + } + + @Override + public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + return null; + } + + @Override + public ResultSet getTypeInfo() throws SQLException { + return null; + } + + @Override + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { + return null; + } + + @Override + public boolean supportsResultSetType(int type) throws SQLException { + return false; + } + + @Override + public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { + return false; + } + + @Override + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean insertsAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean supportsBatchUpdates() throws SQLException { + return false; + } + + @Override + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { + return null; + } + + @Override + public Connection getConnection() throws SQLException { + return this.connection; + } + + @Override + public boolean supportsSavepoints() throws SQLException { + return false; + } + + @Override + public boolean supportsNamedParameters() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleOpenResults() throws SQLException { + return false; + } + + @Override + public boolean supportsGetGeneratedKeys() throws SQLException { + return false; + } + + @Override + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { + return null; + } + + @Override + public boolean supportsResultSetHoldability(int holdability) throws SQLException { + return false; + } + + @Override + public int getResultSetHoldability() throws SQLException { + return 0; + } + + @Override + public int getDatabaseMajorVersion() throws SQLException { + return 0; + } + + @Override + public int getDatabaseMinorVersion() throws SQLException { + return 0; + } + + @Override + public int getJDBCMajorVersion() throws SQLException { + return 0; + } + + @Override + public int getJDBCMinorVersion() throws SQLException { + return 0; + } + + @Override + public int getSQLStateType() throws SQLException { + return 0; + } + + @Override + public boolean locatorsUpdateCopy() throws SQLException { + return false; + } + + @Override + public boolean supportsStatementPooling() throws SQLException { + return false; + } + + @Override + public RowIdLifetime getRowIdLifetime() throws SQLException { + return null; + } + + @Override + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { + return this.connection.createStatement().executeQuery("SHOW SCHEMAS IN " + catalog); + } + + @Override + public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { + return false; + } + + @Override + public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + return false; + } + + @Override + public ResultSet getClientInfoProperties() throws SQLException { + return null; + } + + @Override + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public boolean generatedKeyAlwaysReturned() throws SQLException { + return false; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } +} diff --git a/lib/src/main/java/com/wherobots/db/jdbc/WherobotsJdbcConnection.java b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsJdbcConnection.java index 4c53b84..bdb1915 100644 --- a/lib/src/main/java/com/wherobots/db/jdbc/WherobotsJdbcConnection.java +++ b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsJdbcConnection.java @@ -158,7 +158,7 @@ void retrieveResults(String executionId) { this.session.send(request); } - void cancel(String executionId) { + void cancel(String executionId) throws SQLException { Query query = this.queries.remove(executionId); if (query != null) { query.statement().close(); @@ -173,13 +173,12 @@ public Statement createStatement() { @Override public PreparedStatement prepareStatement(String sql) throws SQLException { - // TODO - throw new SQLFeatureNotSupportedException(); + return new WherobotsPreparedStatement(this, sql); } @Override public CallableStatement prepareCall(String sql) throws SQLException { - throw new SQLFeatureNotSupportedException("Stored procedures are not supported"); + throw new SQLFeatureNotSupportedException("prepareCall: stored procedures are not supported"); } @Override @@ -189,22 +188,22 @@ public String nativeSQL(String sql) { @Override public void setAutoCommit(boolean autoCommit) throws SQLException { - throw new SQLFeatureNotSupportedException("Transactions are not supported"); + // No-op } @Override public boolean getAutoCommit() { - return false; + return true; } @Override public void commit() throws SQLException { - throw new SQLFeatureNotSupportedException("Transactions are not supported"); + // No-op } @Override public void rollback() throws SQLException { - throw new SQLFeatureNotSupportedException("Transactions are not supported"); + // No-op } @Override @@ -219,13 +218,12 @@ public boolean isClosed() { @Override public DatabaseMetaData getMetaData() { - // TODO - return null; + return new WherobotsDatabaseMetaData(this, this.session); } @Override public void setReadOnly(boolean readOnly) throws SQLException { - throw new SQLFeatureNotSupportedException("Read-only mode is not supported"); + throw new SQLFeatureNotSupportedException("setReadOnly: read-only mode is not supported"); } @Override @@ -234,18 +232,18 @@ public boolean isReadOnly() { } @Override - public void setCatalog(String catalog) { - // Ignore, users must specify the catalog in the SQL query. + public void setCatalog(String catalog) throws SQLException { + // No-op } @Override public String getCatalog() { - return ""; + return null; } @Override public void setTransactionIsolation(int level) throws SQLException { - throw new SQLFeatureNotSupportedException("Transactions are not supported"); + throw new SQLFeatureNotSupportedException("setTransactionIsolation: transactions are not supported"); } @Override @@ -265,22 +263,30 @@ public void clearWarnings() { @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { - throw new SQLFeatureNotSupportedException(); + if (resultSetType != ResultSet.TYPE_FORWARD_ONLY || resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { + throw new SQLFeatureNotSupportedException("createStatement: unsupported statement parameters"); + } + + return createStatement(); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - throw new SQLFeatureNotSupportedException(); + if (resultSetType != ResultSet.TYPE_FORWARD_ONLY || resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { + throw new SQLFeatureNotSupportedException("prepareStatement: unsupported statement parameters"); + } + + return prepareStatement(sql); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - throw new SQLFeatureNotSupportedException(); + throw new SQLFeatureNotSupportedException("prepareCall: stored procedures are not supported"); } @Override - public Map> getTypeMap() { - return Map.of(); + public Map> getTypeMap() throws SQLException { + throw new SQLFeatureNotSupportedException("getTypeMap: custom type mappings are not supported"); } @Override @@ -290,62 +296,70 @@ public void setTypeMap(Map> map) { @Override public void setHoldability(int holdability) throws SQLException { - throw new SQLFeatureNotSupportedException("Cursor holdability is not supported"); + throw new SQLFeatureNotSupportedException("setHoldability: cursor holdability is not supported"); } @Override public int getHoldability() throws SQLException { - throw new SQLFeatureNotSupportedException("Cursor holdability is not supported"); + throw new SQLFeatureNotSupportedException("getHoldability: cursor holdability is not supported"); } @Override public Savepoint setSavepoint() throws SQLException { - throw new SQLFeatureNotSupportedException("Transactions are not supported"); + throw new SQLFeatureNotSupportedException("setSavepoint: transactions are not supported"); } @Override public Savepoint setSavepoint(String name) throws SQLException { - throw new SQLFeatureNotSupportedException("Transactions are not supported"); + throw new SQLFeatureNotSupportedException("setSavepoint: transactions are not supported"); } @Override public void rollback(Savepoint savepoint) throws SQLException { - throw new SQLFeatureNotSupportedException("Transactions are not supported"); + throw new SQLFeatureNotSupportedException("rollback: transactions are not supported"); } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { - throw new SQLFeatureNotSupportedException("Transactions are not supported"); + throw new SQLFeatureNotSupportedException("releaseSavepoint: ransactions are not supported"); } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - throw new SQLFeatureNotSupportedException(); + if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { + throw new SQLFeatureNotSupportedException("createStatement: unsupported statement parameters"); + } + + return createStatement(resultSetType, resultSetConcurrency); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - throw new SQLFeatureNotSupportedException(); + if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { + throw new SQLFeatureNotSupportedException("prepareStatement: unsupported statement parameters"); + } + + return prepareStatement(sql, resultSetType, resultSetConcurrency); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - throw new SQLFeatureNotSupportedException("Stored procedures are not supported"); + throw new SQLFeatureNotSupportedException("prepareCall: stored procedures are not supported"); } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { - throw new SQLFeatureNotSupportedException(); + return prepareStatement(sql); } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { - throw new SQLFeatureNotSupportedException(); + throw new SQLFeatureNotSupportedException("prepareStatement(sql, columnIndexes)"); } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { - throw new SQLFeatureNotSupportedException(); + throw new SQLFeatureNotSupportedException("prepareStatement(sql, columnNames)"); } @Override @@ -414,7 +428,7 @@ public void setSchema(String schema) { @Override public String getSchema() { - return ""; + return null; } @Override diff --git a/lib/src/main/java/com/wherobots/db/jdbc/WherobotsJdbcDriver.java b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsJdbcDriver.java index f881881..c1ca124 100644 --- a/lib/src/main/java/com/wherobots/db/jdbc/WherobotsJdbcDriver.java +++ b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsJdbcDriver.java @@ -19,8 +19,12 @@ public class WherobotsJdbcDriver implements Driver { + public static final String DRIVER_NAME = "wherobots"; + public static final int MAJOR_VERSION = 0; + public static final int MINOR_VERSION = 1; + private static final String JDBC_PREFIX = "jdbc:"; - public static final String URL_PREFIX = JDBC_PREFIX + "wherobots://"; + public static final String URL_PREFIX = JDBC_PREFIX + DRIVER_NAME + "://"; public static final String API_KEY_PROP = "apiKey"; public static final String TOKEN_PROP = "token"; @@ -43,9 +47,6 @@ public class WherobotsJdbcDriver implements Driver { public static final Runtime DEFAULT_RUNTIME = Runtime.SEDONA; public static final Region DEFAULT_REGION = Region.AWS_US_WEST_2; - private static final int MAJOR_VERSION = 1; - private static final int MINOR_VERSION = 0; - @Override public Connection connect(String url, Properties info) throws SQLException { String host = DEFAULT_ENDPOINT; diff --git a/lib/src/main/java/com/wherobots/db/jdbc/WherobotsPreparedStatement.java b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsPreparedStatement.java new file mode 100644 index 0000000..edb58ba --- /dev/null +++ b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsPreparedStatement.java @@ -0,0 +1,313 @@ +package com.wherobots.db.jdbc; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.Date; +import java.sql.NClob; +import java.sql.ParameterMetaData; +import java.sql.PreparedStatement; +import java.sql.Ref; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.RowId; +import java.sql.SQLException; +import java.sql.SQLXML; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.Calendar; + +public class WherobotsPreparedStatement extends WherobotsStatement implements PreparedStatement { + + private final String sql; + + public WherobotsPreparedStatement(WherobotsJdbcConnection connection, String sql) { + super(connection); + this.sql = sql; + } + + private String prepare(String sql) { + return sql; + } + + @Override + public boolean execute() throws SQLException { + return execute(prepare(sql)); + } + + @Override + public ResultSet executeQuery() throws SQLException { + return executeQuery(prepare(sql)); + } + + @Override + public int executeUpdate() throws SQLException { + return executeUpdate(prepare(sql)); + } + + @Override + public void clearParameters() throws SQLException { + + } + + @Override + public ParameterMetaData getParameterMetaData() throws SQLException { + // TODO + return null; + } + + @Override + public ResultSetMetaData getMetaData() throws SQLException { + ResultSet resultSet = getResultSet(); + return resultSet != null ? resultSet.getMetaData() : null; + } + + @Override + public void setNull(int parameterIndex, int sqlType) throws SQLException { + + } + + @Override + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + + } + + @Override + public void setByte(int parameterIndex, byte x) throws SQLException { + + } + + @Override + public void setShort(int parameterIndex, short x) throws SQLException { + + } + + @Override + public void setInt(int parameterIndex, int x) throws SQLException { + + } + + @Override + public void setLong(int parameterIndex, long x) throws SQLException { + + } + + @Override + public void setFloat(int parameterIndex, float x) throws SQLException { + + } + + @Override + public void setDouble(int parameterIndex, double x) throws SQLException { + + } + + @Override + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + + } + + @Override + public void setString(int parameterIndex, String x) throws SQLException { + + } + + @Override + public void setBytes(int parameterIndex, byte[] x) throws SQLException { + + } + + @Override + public void setDate(int parameterIndex, Date x) throws SQLException { + + } + + @Override + public void setTime(int parameterIndex, Time x) throws SQLException { + + } + + @Override + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + + } + + @Override + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + + } + + @Override + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + + } + + @Override + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + + } + + @Override + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + + } + + @Override + public void setObject(int parameterIndex, Object x) throws SQLException { + + } + + @Override + public void addBatch() throws SQLException { + + } + + @Override + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + + } + + @Override + public void setRef(int parameterIndex, Ref x) throws SQLException { + + } + + @Override + public void setBlob(int parameterIndex, Blob x) throws SQLException { + + } + + @Override + public void setClob(int parameterIndex, Clob x) throws SQLException { + + } + + @Override + public void setArray(int parameterIndex, Array x) throws SQLException { + + } + + @Override + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + + } + + @Override + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + + } + + @Override + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + + } + + @Override + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + + } + + @Override + public void setURL(int parameterIndex, URL x) throws SQLException { + + } + + @Override + public void setRowId(int parameterIndex, RowId x) throws SQLException { + + } + + @Override + public void setNString(int parameterIndex, String value) throws SQLException { + + } + + @Override + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + + } + + @Override + public void setNClob(int parameterIndex, NClob value) throws SQLException { + + } + + @Override + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + + } + + @Override + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + + } + + @Override + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + + } + + @Override + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + + } + + @Override + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + + } + + @Override + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + + } + + @Override + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + + } + + @Override + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + + } + + @Override + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + + } + + @Override + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + + } + + @Override + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + + } + + @Override + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + + } + + @Override + public void setClob(int parameterIndex, Reader reader) throws SQLException { + + } + + @Override + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + + } + + @Override + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + + } +} diff --git a/lib/src/main/java/com/wherobots/db/jdbc/WherobotsResultSet.java b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsResultSet.java index 3c6a600..6585494 100644 --- a/lib/src/main/java/com/wherobots/db/jdbc/WherobotsResultSet.java +++ b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsResultSet.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.io.StringReader; import java.math.BigDecimal; import java.net.MalformedURLException; import java.net.URL; @@ -95,7 +96,9 @@ public boolean wasNull() { private T get(int columnIndex, Class cls) throws SQLException { try { Preconditions.checkState(currentVectorRow >= 0 && currentVectorRow < root.getRowCount()); - Object value = root.getVector(columnIndex).getObject(currentVectorRow); + + // Column index is 1-based in JDBC + Object value = root.getVector(columnIndex - 1).getObject(currentVectorRow); this.wasNull = value == null; return cls.cast(value); } catch (Exception e) { @@ -189,7 +192,9 @@ private T get(String columnLabel, Class cls) throws SQLException { Object value = root.getVector(columnLabel).getObject(currentVectorRow); return cls.cast(value); } catch (Exception e) { - throw new SQLException(e); + throw new SQLException( + String.format("Error accessing column %s from current row %d of resultset", columnLabel, currentRow), + e); } } @@ -235,7 +240,7 @@ public double getDouble(String columnLabel) throws SQLException { @Override public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { - throw new SQLFeatureNotSupportedException(); + throw new SQLFeatureNotSupportedException("BigDecimal isn't supported"); } @Override @@ -295,12 +300,12 @@ public ResultSetMetaData getMetaData() { @Override public Object getObject(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(); + return get(columnIndex, Object.class); } @Override public Object getObject(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(); + return get(columnLabel, Object.class); } @Override @@ -310,12 +315,12 @@ public int findColumn(String columnLabel) throws SQLException { @Override public Reader getCharacterStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException(); + return new StringReader(getString(columnIndex)); } @Override public Reader getCharacterStream(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException(); + return new StringReader(getString(columnLabel)); } @Override diff --git a/lib/src/main/java/com/wherobots/db/jdbc/WherobotsStatement.java b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsStatement.java index 64a48a5..5fb452f 100644 --- a/lib/src/main/java/com/wherobots/db/jdbc/WherobotsStatement.java +++ b/lib/src/main/java/com/wherobots/db/jdbc/WherobotsStatement.java @@ -26,7 +26,10 @@ public class WherobotsStatement implements Statement { private String executionId; private ResultSet results; - private int updateCount = 0; + private int updateCount = -1; + + private boolean closeOnCompletion = false; + private boolean closed = false; public WherobotsStatement(WherobotsJdbcConnection connection) { this.connection = connection; @@ -56,7 +59,11 @@ public int executeUpdate(String sql) throws SQLException { } @Override - public void close() { + public void close() throws SQLException { + if (this.results != null) { + this.results.close(); + } + this.closed = true; } @Override @@ -66,7 +73,7 @@ public int getMaxFieldSize() { @Override public void setMaxFieldSize(int max) throws SQLException { - throw new SQLFeatureNotSupportedException(); + // Ignored } @Override @@ -85,7 +92,9 @@ public void setMaxRows(int max) { @Override public void setEscapeProcessing(boolean enable) throws SQLException { - throw new SQLFeatureNotSupportedException(); + if (enable) { + throw new SQLFeatureNotSupportedException("setEscapeProcessing: escape processing is not supported"); + } } @Override @@ -103,7 +112,7 @@ public void setQueryTimeout(int seconds) { } @Override - public void cancel() { + public void cancel() throws SQLException { if (this.executionId != null) { this.connection.cancel(this.executionId); } @@ -166,12 +175,18 @@ public int getUpdateCount() { @Override public boolean getMoreResults() throws SQLException { - throw new SQLFeatureNotSupportedException("Multiple result sets are not supported"); + if (this.results != null) { + this.results.close(); + if (this.closeOnCompletion) { + close(); + } + } + return false; } @Override public void setFetchDirection(int direction) throws SQLException { - throw new SQLFeatureNotSupportedException(); + // Ignored } @Override @@ -181,7 +196,7 @@ public int getFetchDirection() { @Override public void setFetchSize(int rows) throws SQLException { - throw new SQLFeatureNotSupportedException(); + // Ignored } @Override @@ -221,11 +236,11 @@ public Connection getConnection() { @Override public boolean getMoreResults(int current) throws SQLException { - throw new SQLFeatureNotSupportedException("Multiple result sets are not supported"); + return getMoreResults(); } @Override - public ResultSet getGeneratedKeys() throws SQLException { + public ResultSet getGeneratedKeys() { return null; } @@ -266,12 +281,12 @@ public int getResultSetHoldability() throws SQLException { @Override public boolean isClosed() { - return false; + return closed; } @Override public void setPoolable(boolean poolable) throws SQLException { - throw new SQLFeatureNotSupportedException(); + // Ignored } @Override @@ -281,12 +296,12 @@ public boolean isPoolable() { @Override public void closeOnCompletion() throws SQLException { - throw new SQLFeatureNotSupportedException(); + this.closeOnCompletion = true; } @Override public boolean isCloseOnCompletion() { - return false; + return closeOnCompletion; } @Override