diff --git a/jdbc-v2/src/main/java/com/clickhouse/jdbc/ResultSetImpl.java b/jdbc-v2/src/main/java/com/clickhouse/jdbc/ResultSetImpl.java index fa6cd26a0..944b43801 100644 --- a/jdbc-v2/src/main/java/com/clickhouse/jdbc/ResultSetImpl.java +++ b/jdbc-v2/src/main/java/com/clickhouse/jdbc/ResultSetImpl.java @@ -5,6 +5,7 @@ import com.clickhouse.client.api.query.QueryResponse; import com.clickhouse.data.ClickHouseDataType; import com.clickhouse.jdbc.internal.ExceptionUtils; +import com.clickhouse.jdbc.internal.FeatureManager; import com.clickhouse.jdbc.internal.JdbcUtils; import com.clickhouse.jdbc.metadata.ResultSetMetaDataImpl; import org.slf4j.Logger; @@ -26,7 +27,6 @@ import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLType; import java.sql.SQLWarning; import java.sql.SQLXML; @@ -35,7 +35,6 @@ import java.sql.Timestamp; import java.time.ZonedDateTime; import java.util.Calendar; -import java.util.Collection; import java.util.Map; public class ResultSetImpl implements ResultSet, JdbcV2Wrapper { @@ -48,10 +47,20 @@ public class ResultSetImpl implements ResultSet, JdbcV2Wrapper { private boolean wasNull; private final Calendar defaultCalendar; - public ResultSetImpl(StatementImpl parentStatement, QueryResponse response, ClickHouseBinaryFormatReader reader) { + private final FeatureManager featureManager; + + private static final int AFTER_LAST = -1; + private static final int BEFORE_FIRST = 0; + private static final int FIRST_ROW = 1; + private int rowPos; + + private int fetchSize; + + public ResultSetImpl(StatementImpl parentStatement, QueryResponse response, ClickHouseBinaryFormatReader reader) throws SQLException { this.parentStatement = parentStatement; this.response = response; this.reader = reader; + this.featureManager = new FeatureManager(parentStatement.getConnection().getJdbcConfig()); TableSchema tableMetadata = reader.getSchema(); // Result set contains columns from one database (there is a special table engine 'Merge' to do cross DB queries) @@ -60,17 +69,20 @@ public ResultSetImpl(StatementImpl parentStatement, QueryResponse response, Clic JdbcUtils.DATA_TYPE_CLASS_MAP); this.closed = false; this.wasNull = false; - this.defaultCalendar = parentStatement.connection.defaultCalendar; + this.defaultCalendar = parentStatement.getConnection().defaultCalendar; + this.rowPos = BEFORE_FIRST; + this.fetchSize = parentStatement.getFetchSize(); } - protected ResultSetImpl(ResultSetImpl resultSet) { + protected ResultSetImpl(ResultSetImpl resultSet) throws SQLException{ this.parentStatement = resultSet.parentStatement; this.response = resultSet.response; this.reader = resultSet.reader; this.metaData = resultSet.metaData; this.closed = false; this.wasNull = false; - this.defaultCalendar = parentStatement.connection.defaultCalendar; + this.defaultCalendar = parentStatement.getConnection().defaultCalendar; + this.featureManager = new FeatureManager(parentStatement.getConnection().getJdbcConfig()); } private void checkClosed() throws SQLException { @@ -97,7 +109,13 @@ public boolean next() throws SQLException { checkClosed(); try { - return reader.next() != null; + Object readerRow = reader.next(); + if (readerRow != null) { + rowPos++; + } else { + rowPos = AFTER_LAST; + } + return readerRow != null; } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } @@ -402,10 +420,7 @@ public Timestamp getTimestamp(String columnLabel) throws SQLException { @Override public InputStream getAsciiStream(String columnLabel) throws SQLException { checkClosed(); - //TODO: Add this to ClickHouseBinaryFormatReader - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("AsciiStream is not yet supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("getAsciiStream"); return null; } @@ -419,10 +434,7 @@ public InputStream getUnicodeStream(String columnLabel) throws SQLException { @Override public InputStream getBinaryStream(String columnLabel) throws SQLException { checkClosed(); - //TODO: implement - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("BinaryStream is not yet supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("getBinaryStream"); return null; } @@ -441,6 +453,7 @@ public void clearWarnings() throws SQLException { @Override public String getCursorName() throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("getCursorName"); return ""; } @@ -477,9 +490,7 @@ public int findColumn(String columnLabel) throws SQLException { @Override public Reader getCharacterStream(int columnIndex) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("CharacterStream is not yet supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("getCharacterStream"); return null; } @@ -487,9 +498,7 @@ public Reader getCharacterStream(int columnIndex) throws SQLException { @Override public Reader getCharacterStream(String columnLabel) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("CharacterStream is not yet supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("getCharacterStream"); return null; } @@ -518,59 +527,43 @@ public BigDecimal getBigDecimal(String columnLabel) throws SQLException { @Override public boolean isBeforeFirst() throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("isBeforeFirst is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } - - return false; + return rowPos == BEFORE_FIRST; } @Override public boolean isAfterLast() throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("isAfterLast is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } - - return false; + return rowPos == AFTER_LAST; } @Override public boolean isFirst() throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("isFirst is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } - - return false; + return rowPos == FIRST_ROW; } @Override public boolean isLast() throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("isLast is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } - - return false; + return !reader.hasNext() && rowPos != AFTER_LAST; } @Override public void beforeFirst() throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("beforeFirst"); } @Override public void afterLast() throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("afterLast"); } @Override public boolean first() throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("first is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("first"); return false; } @@ -578,10 +571,7 @@ public boolean first() throws SQLException { @Override public boolean last() throws SQLException { checkClosed(); - - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("last is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("last"); return false; } @@ -589,20 +579,13 @@ public boolean last() throws SQLException { @Override public int getRow() throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("getRow is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } - - return 0; + return rowPos == AFTER_LAST ? 0 : rowPos; } @Override public boolean absolute(int row) throws SQLException { checkClosed(); - - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("absolute is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("absolute"); return false; } @@ -610,9 +593,7 @@ public boolean absolute(int row) throws SQLException { @Override public boolean relative(int rows) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("relative is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("relative"); return false; } @@ -620,9 +601,7 @@ public boolean relative(int rows) throws SQLException { @Override public boolean previous() throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("previous is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("previous"); return false; } @@ -636,20 +615,24 @@ public int getFetchDirection() throws SQLException { @Override public void setFetchDirection(int direction) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("setFetchDirection is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); + if (direction != ResultSet.FETCH_FORWARD) { + throw new SQLException("This result set object is of FORWARD ONLY type. Only ResultSet.FETCH_FORWARD is allowed as fetchDirection."); } } @Override public int getFetchSize() throws SQLException { checkClosed(); - return 0; + return fetchSize; } @Override public void setFetchSize(int rows) throws SQLException { checkClosed(); + if (rows < 0) { + throw new SQLException("Number of rows should be a positive integer"); + } + fetchSize = rows; } @Override @@ -667,9 +650,7 @@ public int getConcurrency() throws SQLException { @Override public boolean rowUpdated() throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("rowUpdated"); return false; } @@ -677,9 +658,7 @@ public boolean rowUpdated() throws SQLException { @Override public boolean rowInserted() throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("rowInserted"); return false; } @@ -687,9 +666,7 @@ public boolean rowInserted() throws SQLException { @Override public boolean rowDeleted() throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("rowDeleted"); return false; } @@ -792,188 +769,176 @@ public void updateObject(int columnIndex, Object x) throws SQLException { @Override public void updateNull(String columnLabel) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateNull"); + } @Override public void updateBoolean(String columnLabel, boolean x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateBoolean"); + } @Override public void updateByte(String columnLabel, byte x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateByte"); + } @Override public void updateShort(String columnLabel, short x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateShort"); + } @Override public void updateInt(String columnLabel, int x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateInt"); + } @Override public void updateLong(String columnLabel, long x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateLong"); + } @Override public void updateFloat(String columnLabel, float x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateFloat"); + } @Override public void updateDouble(String columnLabel, double x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateDouble"); + } @Override public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateBigDecimal"); + } @Override public void updateString(String columnLabel, String x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateString"); + } @Override public void updateBytes(String columnLabel, byte[] x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateBytes"); + } @Override public void updateDate(String columnLabel, Date x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateDate"); + } @Override public void updateTime(String columnLabel, Time x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateTime"); + } @Override public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateTimestamp"); + } @Override public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateAsciiStream"); + } @Override public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateBinaryStream"); + } @Override public void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateCharacterStream"); + } @Override public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateObject"); + } @Override public void updateObject(String columnLabel, Object x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateObject"); + } @Override public void insertRow() throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("insertRow"); } @Override public void updateRow() throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("updateRow"); } @Override public void deleteRow() throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("deleteRow"); } @Override public void refreshRow() throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("refreshRow"); } @Override public void cancelRowUpdates() throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("cancelRowUpdates"); } @Override public void moveToInsertRow() throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("moveToInsertRow"); } @Override public void moveToCurrentRow() throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("moveToCurrentRow"); } @Override @@ -1017,9 +982,7 @@ public Object getObject(String columnLabel, Map> map) throws SQ @Override public Ref getRef(String columnLabel) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Ref is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("getRef"); return null; } @@ -1027,9 +990,7 @@ public Ref getRef(String columnLabel) throws SQLException { @Override public Blob getBlob(String columnLabel) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Blob is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("getBlob"); return null; } @@ -1037,9 +998,7 @@ public Blob getBlob(String columnLabel) throws SQLException { @Override public Clob getClob(String columnLabel) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Clob is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("getClob"); return null; } @@ -1149,9 +1108,7 @@ public void updateRef(int columnIndex, Ref x) throws SQLException { @Override public void updateRef(String columnLabel, Ref x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateRef"); } @Override @@ -1162,9 +1119,7 @@ public void updateBlob(int columnIndex, Blob x) throws SQLException { @Override public void updateBlob(String columnLabel, Blob x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateBlob"); } @Override @@ -1175,9 +1130,7 @@ public void updateClob(int columnIndex, Clob x) throws SQLException { @Override public void updateClob(String columnLabel, Clob x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateClob"); } @Override @@ -1188,9 +1141,7 @@ public void updateArray(int columnIndex, java.sql.Array x) throws SQLException { @Override public void updateArray(String columnLabel, java.sql.Array x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateArray"); } @Override @@ -1201,6 +1152,7 @@ public RowId getRowId(int columnIndex) throws SQLException { @Override public RowId getRowId(String columnLabel) throws SQLException { checkClosed(); + featureManager.unsupportedFeatureThrow("getRowId"); return null; } @@ -1212,9 +1164,7 @@ public void updateRowId(int columnIndex, RowId x) throws SQLException { @Override public void updateRowId(String columnLabel, RowId x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateRowId"); } @Override @@ -1236,9 +1186,7 @@ public void updateNString(int columnIndex, String nString) throws SQLException { @Override public void updateNString(String columnLabel, String nString) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateNString"); } @Override @@ -1249,9 +1197,7 @@ public void updateNClob(int columnIndex, NClob nClob) throws SQLException { @Override public void updateNClob(String columnLabel, NClob nClob) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateNClob"); } @Override @@ -1262,9 +1208,7 @@ public NClob getNClob(int columnIndex) throws SQLException { @Override public NClob getNClob(String columnLabel) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("NClob is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("getNClob"); return null; } @@ -1277,9 +1221,7 @@ public SQLXML getSQLXML(int columnIndex) throws SQLException { @Override public SQLXML getSQLXML(String columnLabel) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("SQLXML is not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("getSQLXML"); return null; } @@ -1292,9 +1234,7 @@ public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException @Override public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateSQLXML"); } @Override @@ -1335,9 +1275,7 @@ public void updateNCharacterStream(int columnIndex, Reader x, long length) throw @Override public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateNCharacterStream"); } @Override @@ -1358,25 +1296,19 @@ public void updateCharacterStream(int columnIndex, Reader x, long length) throws @Override public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateAsciiStream"); } @Override public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateBinaryStream"); } @Override public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateCharacterStream"); } @Override @@ -1387,9 +1319,7 @@ public void updateBlob(int columnIndex, InputStream inputStream, long length) th @Override public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateBlob"); } @Override @@ -1400,9 +1330,7 @@ public void updateClob(int columnIndex, Reader reader, long length) throws SQLEx @Override public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateClob"); } @Override @@ -1413,9 +1341,7 @@ public void updateNClob(int columnIndex, Reader reader, long length) throws SQLE @Override public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateNClob"); } @Override @@ -1426,9 +1352,7 @@ public void updateNCharacterStream(int columnIndex, Reader x) throws SQLExceptio @Override public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateNCharacterStream"); } @Override @@ -1449,25 +1373,19 @@ public void updateCharacterStream(int columnIndex, Reader x) throws SQLException @Override public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateAsciiStream"); } @Override public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateBinaryStream"); } @Override public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateCharacterStream"); } @Override @@ -1478,9 +1396,7 @@ public void updateBlob(int columnIndex, InputStream inputStream) throws SQLExcep @Override public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateBlob"); } @Override @@ -1491,9 +1407,7 @@ public void updateClob(int columnIndex, Reader reader) throws SQLException { @Override public void updateClob(String columnLabel, Reader reader) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateClob"); } @Override @@ -1504,9 +1418,7 @@ public void updateNClob(int columnIndex, Reader reader) throws SQLException { @Override public void updateNClob(String columnLabel, Reader reader) throws SQLException { checkClosed(); - if (!parentStatement.connection.config.isIgnoreUnsupportedRequests()) { - throw new SQLFeatureNotSupportedException("Writes are not supported.", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); - } + featureManager.unsupportedFeatureThrow("updateNClob"); } @Override @@ -1560,7 +1472,7 @@ public void updateObject(int columnIndex, Object x, SQLType targetSqlType, int s @Override public void updateObject(String columnLabel, Object x, SQLType targetSqlType, int scaleOrLength) throws SQLException { checkClosed(); - ResultSet.super.updateObject(columnLabel, x, targetSqlType, scaleOrLength); + featureManager.unsupportedFeatureThrow("updateObject"); } @Override @@ -1571,6 +1483,6 @@ public void updateObject(int columnIndex, Object x, SQLType targetSqlType) throw @Override public void updateObject(String columnLabel, Object x, SQLType targetSqlType) throws SQLException { checkClosed(); - ResultSet.super.updateObject(columnLabel, x, targetSqlType); + featureManager.unsupportedFeatureThrow("updateObject"); } } diff --git a/jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java b/jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java index 3e1a64848..cbe687809 100644 --- a/jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java +++ b/jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java @@ -44,6 +44,8 @@ public class StatementImpl implements Statement, JdbcV2Wrapper { private int maxFieldSize; private boolean escapeProcessingEnabled; + private int fetchSize = 1; + // settings local to a statement protected QuerySettings localSettings; @@ -129,6 +131,11 @@ protected ResultSetImpl executeQueryImpl(String sql, QuerySettings settings) thr // release before this one completes. if (resultSetAutoClose) { closeCurrentResultSet(); + // There is a feature `closeOnComplete` that dictate closing statement when all + // result sets are closed. Call to `closeCurrentResultSet` will trigger this statement + // closure. But it should not happen because this was introduces instead of spec and will be remove in future/ + // So we need make this statement open again because we going to create a new result set. + this.closed = false; } QuerySettings mergedSettings = QuerySettings.merge(settings, new QuerySettings()); @@ -362,12 +369,16 @@ public int getFetchDirection() throws SQLException { @Override public void setFetchSize(int rows) throws SQLException { ensureOpen(); + if (rows < 0) { + throw new SQLException("rows should be greater than 0."); + } + this.fetchSize = rows; } @Override public int getFetchSize() throws SQLException { ensureOpen(); - return 0; + return fetchSize; } @Override diff --git a/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/FeatureManager.java b/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/FeatureManager.java new file mode 100644 index 000000000..25670c41e --- /dev/null +++ b/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/FeatureManager.java @@ -0,0 +1,20 @@ +package com.clickhouse.jdbc.internal; + +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; + +public class FeatureManager { + + private final JdbcConfiguration configuration; + + public FeatureManager(JdbcConfiguration configuration) { + this.configuration = configuration; + } + + public void unsupportedFeatureThrow(String methodName) throws SQLException { + if (!configuration.isIgnoreUnsupportedRequests()) { + throw new SQLFeatureNotSupportedException(methodName + " is not supported.", + ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED); + } + } +} diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/ResultSetImplTest.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/ResultSetImplTest.java index ebdc94a3b..bb3c8f3b2 100644 --- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/ResultSetImplTest.java +++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/ResultSetImplTest.java @@ -1,14 +1,32 @@ package com.clickhouse.jdbc; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import org.testng.Assert; +import org.testng.annotations.Test; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.math.BigDecimal; +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; import java.sql.Connection; +import java.sql.Date; +import java.sql.JDBCType; +import java.sql.NClob; +import java.sql.Ref; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.Properties; -import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; public class ResultSetImplTest extends JdbcIntegrationTest { @@ -35,4 +53,296 @@ public void shouldReturnColumnIndex() throws SQLException { } } } + + @Test(groups = {"integration"}) + public void testUnsupportedOperations() throws Throwable { + + boolean[] throwUnsupportedException = new boolean[]{false, true}; + + for (boolean flag : throwUnsupportedException) { + Properties props = new Properties(); + if (flag) { + props.setProperty(DriverProperties.IGNORE_UNSUPPORTED_VALUES.getKey(), "true"); + } + + try (Connection conn = this.getJdbcConnection(props); Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT 1")) { + Assert.ThrowingRunnable[] rsUnsupportedMethods = new Assert.ThrowingRunnable[]{ + rs::first, + rs::afterLast, + rs::beforeFirst, + () -> rs.absolute(-1), + () -> rs.relative(-1), + rs::moveToCurrentRow, + rs::moveToInsertRow, + rs::last, + rs::previous, + rs::refreshRow, + () -> rs.updateBoolean("col1", true), + () -> rs.updateByte("col1", (byte) 1), + () -> rs.updateShort("col1", (short) 1), + () -> rs.updateInt("col1", 1), + () -> rs.updateLong("col1", 1L), + () -> rs.updateFloat("col1", 1.1f), + () -> rs.updateDouble("col1", 1.1), + () -> rs.updateBigDecimal("col1", BigDecimal.valueOf(1.1)), + () -> rs.updateString("col1", "test"), + () -> rs.updateNString("col1", "test"), + () -> rs.updateBytes("col1", new byte[1]), + () -> rs.updateDate("col1", Date.valueOf("2020-01-01")), + () -> rs.updateTime("col1", Time.valueOf("12:34:56")), + () -> rs.updateTimestamp("col1", Timestamp.valueOf("2020-01-01 12:34:56.789123")), + () -> rs.updateBlob("col1", (Blob) null), + () -> rs.updateClob("col1", new StringReader("test")), + () -> rs.updateNClob("col1", new StringReader("test")), + + () -> rs.updateBoolean(1, true), + () -> rs.updateByte(1, (byte) 1), + () -> rs.updateShort(1, (short) 1), + () -> rs.updateInt(1, 1), + () -> rs.updateLong(1, 1L), + () -> rs.updateFloat(1, 1.1f), + () -> rs.updateDouble(1, 1.1), + () -> rs.updateBigDecimal(1, BigDecimal.valueOf(1.1)), + () -> rs.updateString(1, "test"), + () -> rs.updateNString(1, "test"), + () -> rs.updateBytes(1, new byte[1]), + () -> rs.updateDate(1, Date.valueOf("2020-01-01")), + () -> rs.updateTime(1, Time.valueOf("12:34:56")), + () -> rs.updateTimestamp(1, Timestamp.valueOf("2020-01-01 12:34:56.789123")), + () -> rs.updateBlob(1, (Blob) null), + () -> rs.updateClob(1, new StringReader("test")), + () -> rs.updateNClob(1, new StringReader("test")), + () -> rs.updateSQLXML(1, null), + () -> rs.updateObject(1, 1), + () -> rs.updateObject("col1", 1), + () -> rs.updateObject(1, "test", Types.INTEGER), + () -> rs.updateObject("col1", "test", Types.INTEGER), + () -> rs.updateObject(1, "test", JDBCType.INTEGER), + () -> rs.updateObject("col1", "test", JDBCType.INTEGER), + () -> rs.updateObject(1, "test", JDBCType.INTEGER, 1), + () -> rs.updateCharacterStream(1, new StringReader("test"), 1), + () -> rs.updateCharacterStream("col1", new StringReader("test")), + () -> rs.updateCharacterStream("col1", new StringReader("test"), 1), + () -> rs.updateCharacterStream(1, new StringReader("test"), 1L), + () -> rs.updateCharacterStream("col1", new StringReader("test"), 1L), + () -> rs.updateCharacterStream(1, new StringReader("test")), + () -> rs.updateCharacterStream("col1", new StringReader("test")), + () -> rs.updateNCharacterStream(1, new StringReader("test"), 1), + () -> rs.updateNCharacterStream("col1", new StringReader("test"), 1), + () -> rs.updateNCharacterStream(1, new StringReader("test"), 1L), + () -> rs.updateNCharacterStream("col1", new StringReader("test"), 1L), + () -> rs.updateNCharacterStream(1, new StringReader("test")), + () -> rs.updateNCharacterStream("col1", new StringReader("test")), + () -> rs.updateBlob(1, (InputStream) null), + () -> rs.updateBlob("col1", (InputStream) null), + () -> rs.updateBlob(1, (InputStream) null, -1), + () -> rs.updateBlob("col1", (InputStream) null, -1), + () -> rs.updateBinaryStream(1, (InputStream) null), + () -> rs.updateBinaryStream("col1", (InputStream) null), + () -> rs.updateBinaryStream(1, (InputStream) null, -1), + () -> rs.updateBinaryStream("col1", (InputStream) null, -1), + () -> rs.updateBinaryStream(1, (InputStream) null, -1L), + () -> rs.updateBinaryStream("col1", (InputStream) null, -1L), + () -> rs.updateAsciiStream(1, (InputStream) null), + () -> rs.updateAsciiStream("col1", (InputStream) null), + () -> rs.updateAsciiStream(1, (InputStream) null, -1), + () -> rs.updateAsciiStream("col1", (InputStream) null, -1), + () -> rs.updateAsciiStream(1, (InputStream) null, -1L), + () -> rs.updateAsciiStream("col1", (InputStream) null, -1L), + () -> rs.updateClob(1, (Reader) null), + () -> rs.updateClob("col1", (Reader) null), + () -> rs.updateClob(1, (Reader) null, -1), + () -> rs.updateClob("col1", (Reader) null, -1), + () -> rs.updateClob(1, (Reader) null, -1L), + () -> rs.updateClob("col1", (Reader) null, -1L), + () -> rs.updateNClob(1, (Reader) null), + () -> rs.updateNClob("col1", (Reader) null), + () -> rs.updateNClob(1, (NClob) null), + () -> rs.updateNClob("col1", (NClob) null), + () -> rs.updateNClob(1, (Reader) null, -1), + () -> rs.updateNClob("col1", (Reader) null, -1), + () -> rs.updateNClob(1, (Reader) null, -1L), + () -> rs.updateNClob("col1", (Reader) null, -1L), + () -> rs.updateRef(1, (Ref) null), + () -> rs.updateRef("col1", (Ref) null), + () -> rs.updateArray(1, (Array) null), + () -> rs.updateArray("col1", (Array) null), + () -> rs.getSQLXML(1), + () -> rs.getSQLXML("col1"), + () -> rs.getBlob(1), + () -> rs.getBlob("col1"), + () -> rs.getClob(1), + () -> rs.getClob("col1"), + () -> rs.getNClob(1), + () -> rs.getNClob("col1"), + () -> rs.getRef(1), + () -> rs.getRef("col1"), + () -> rs.getRowId(1), + () -> rs.getRowId("col1"), + rs::cancelRowUpdates, + () -> rs.updateNull(1), + () -> rs.updateNull("col1"), + () -> rs.updateRowId(1, null), + () -> rs.updateRowId("col1", null), + () -> rs.updateClob(1, (Clob) null), + () -> rs.updateClob("col1", (Clob) null), + rs::updateRow, + rs::insertRow, + rs::deleteRow, + rs::rowDeleted, + rs::rowInserted, + rs::rowUpdated, + rs::getCursorName, + }; + + for (Assert.ThrowingRunnable op : rsUnsupportedMethods) { + if (!flag) { + Assert.assertThrows(SQLFeatureNotSupportedException.class, op); + } else { + op.run(); + } + } + } + } + } + + + @Test(groups = {"integration"}) + public void testCursorPosition() throws SQLException { + try (Connection conn = getJdbcConnection(); Statement stmt = conn.createStatement()) { + try (ResultSet rs = stmt.executeQuery("select number from system.numbers LIMIT 2")) { + Assert.assertTrue(rs.isBeforeFirst()); + Assert.assertFalse(rs.isAfterLast()); + Assert.assertFalse(rs.isFirst()); + Assert.assertFalse(rs.isLast()); + Assert.assertEquals(rs.getRow(), 0); + + rs.next(); + + Assert.assertFalse(rs.isBeforeFirst()); + Assert.assertFalse(rs.isAfterLast()); + Assert.assertTrue(rs.isFirst()); + Assert.assertFalse(rs.isLast()); + Assert.assertEquals(rs.getRow(), 1); + + rs.next(); + + Assert.assertFalse(rs.isBeforeFirst()); + Assert.assertFalse(rs.isAfterLast()); + Assert.assertFalse(rs.isFirst()); + Assert.assertTrue(rs.isLast()); + Assert.assertEquals(rs.getRow(), 2); + + rs.next(); + + Assert.assertFalse(rs.isBeforeFirst()); + Assert.assertTrue(rs.isAfterLast()); + Assert.assertFalse(rs.isFirst()); + Assert.assertFalse(rs.isLast()); + Assert.assertEquals(rs.getRow(), 0); + + } + } + } + + + @Test(groups = {"integration"}) + public void testFetchDirectionsAndSize() throws SQLException { + try (Connection conn = getJdbcConnection(); Statement stmt = conn.createStatement()) { + try (ResultSet rs = stmt.executeQuery("select number from system.numbers LIMIT 2")) { + Assert.assertEquals(rs.getFetchDirection(), ResultSet.FETCH_FORWARD); + Assert.expectThrows(SQLException.class, () -> rs.setFetchDirection(ResultSet.FETCH_REVERSE)); + Assert.expectThrows(SQLException.class, () -> rs.setFetchDirection(ResultSet.FETCH_UNKNOWN)); + rs.setFetchDirection(ResultSet.FETCH_FORWARD); + + Assert.assertEquals(rs.getFetchSize(), 1); + rs.setFetchSize(10); + Assert.assertEquals(rs.getFetchSize(), 10); + Assert.expectThrows(SQLException.class, () -> rs.setFetchSize(-10)); + } + } + } + + @Test(groups = {"integration"}) + public void testConstants() throws SQLException { + try (Connection conn = getJdbcConnection(); Statement stmt = conn.createStatement()) { + try (ResultSet rs = stmt.executeQuery("select number from system.numbers LIMIT 2")) { + Assert.assertSame(rs.getStatement(), stmt); + Assert.assertEquals(rs.getType(), ResultSet.TYPE_FORWARD_ONLY); + Assert.assertEquals(rs.getConcurrency(), ResultSet.CONCUR_READ_ONLY); + Assert.assertEquals(rs.getHoldability(), ResultSet.HOLD_CURSORS_OVER_COMMIT); + } + } + } + + @Test(groups = {"integration"}) + public void testWasNull() throws SQLException { + try (Connection conn = getJdbcConnection(); Statement stmt = conn.createStatement()) { + final String sql = "select NULL::Nullable(%s) as v1"; + + try (ResultSet rs = stmt.executeQuery(sql.formatted("Int64"))) { + rs.next(); + Assert.assertFalse(rs.wasNull()); + + Assert.assertEquals(rs.getByte(1), (byte) 0); + Assert.assertTrue(rs.wasNull()); + Assert.assertEquals(rs.getByte("v1"), (byte) 0); + Assert.assertTrue(rs.wasNull()); + + Assert.assertEquals(rs.getShort(1), (short) 0); + Assert.assertTrue(rs.wasNull()); + Assert.assertEquals(rs.getShort("v1"), (short) 0); + Assert.assertTrue(rs.wasNull()); + + Assert.assertEquals(rs.getInt(1), 0); + Assert.assertTrue(rs.wasNull()); + Assert.assertEquals(rs.getInt("v1"), 0); + Assert.assertTrue(rs.wasNull()); + + Assert.assertEquals(rs.getLong(1), 0L); + Assert.assertTrue(rs.wasNull()); + Assert.assertEquals(rs.getLong("v1"), 0L); + Assert.assertTrue(rs.wasNull()); + + Assert.assertNull(rs.getBigDecimal(1)); + Assert.assertTrue(rs.wasNull()); + Assert.assertNull(rs.getBigDecimal("v1")); + Assert.assertTrue(rs.wasNull()); + + Assert.assertEquals(rs.getFloat(1), 0f); + Assert.assertTrue(rs.wasNull()); + Assert.assertEquals(rs.getFloat("v1"), 0f); + Assert.assertTrue(rs.wasNull()); + + Assert.assertEquals(rs.getDouble(1), 0d); + Assert.assertTrue(rs.wasNull()); + Assert.assertEquals(rs.getDouble("v1"), 0d); + Assert.assertTrue(rs.wasNull()); + + Assert.assertEquals(rs.getBoolean(1), false); + Assert.assertTrue(rs.wasNull()); + Assert.assertEquals(rs.getBoolean("v1"), false); + Assert.assertTrue(rs.wasNull()); + } + } + } + + @Test(groups = {"integration"}) + public void testGetMetadata() throws SQLException { + try (Connection conn = getJdbcConnection(); Statement stmt = conn.createStatement()) { + try (ResultSet rs = stmt.executeQuery("select '1'::Int32 as v1, 'test' as v2 ")) { + + int v1ColumnIndex = rs.findColumn("v1"); + int v2ColumnIndex = rs.findColumn("v2"); + + ResultSetMetaData metaData = rs.getMetaData(); + Assert.assertEquals(metaData.getColumnCount(), 2); + Assert.assertEquals(metaData.getColumnType(v1ColumnIndex), Types.INTEGER); + Assert.assertEquals(metaData.getColumnType(v2ColumnIndex), Types.VARCHAR); + Assert.assertEquals(metaData.getColumnTypeName(v1ColumnIndex), "Int32"); + Assert.assertEquals(metaData.getColumnTypeName(v2ColumnIndex), "String"); + } + } + } } diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/StatementTest.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/StatementTest.java index fa45ab756..520177545 100644 --- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/StatementTest.java +++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/StatementTest.java @@ -958,7 +958,7 @@ public void testVariousSimpleMethods() throws Exception { stmt.setQueryTimeout(100); Assert.assertEquals(stmt.getQueryTimeout(), 100); stmt.setFetchSize(100); - Assert.assertEquals(stmt.getFetchSize(), 0); // we ignore this hint + Assert.assertEquals(stmt.getFetchSize(), 100); // we ignore this hint Assert.assertEquals(stmt.getResultSetConcurrency(), ResultSet.CONCUR_READ_ONLY); Assert.assertEquals(stmt.getResultSetType(), ResultSet.TYPE_FORWARD_ONLY); Assert.assertNotNull(stmt.getConnection());