Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import java.nio.ByteBuffer;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.sql.Types;
Expand Down Expand Up @@ -260,6 +261,95 @@ public void testQuery() throws Exception {
verify(fetchResultsResp, times(0)).getStatus();
}

/**
* The tree-model time pseudo-column is addressed by a negative TsBlock column index. getLong,
* getString and getObject handle it; the strictly-typed getters used to fall through to
* TsBlock.getColumn(-1) and escape as an unchecked ArrayIndexOutOfBoundsException instead of the
* SQLException a JDBC caller can handle. getDate delegates to getInt, so it is affected too.
*/
@SuppressWarnings("resource")
@Test
public void testTimeColumnRejectedByStrictlyTypedGetters() throws Exception {
try (ResultSet resultSet = executeAndFetchTreeModelResultSet()) {
Assert.assertEquals(1, resultSet.findColumn("Time"));
Assert.assertTrue(resultSet.next());

// The getters that support the time column keep working.
Assert.assertEquals(2L, resultSet.getLong(1));
Assert.assertEquals("2", resultSet.getString(1));
Assert.assertEquals(new Timestamp(2), resultSet.getObject(1));
Assert.assertEquals(new Timestamp(2), resultSet.getTimestamp(1));

// The strictly-typed ones must report a SQLException, not an unchecked exception.
assertTimeColumnRejected(() -> resultSet.getBoolean(1));
assertTimeColumnRejected(() -> resultSet.getInt(1));
assertTimeColumnRejected(() -> resultSet.getFloat(1));
assertTimeColumnRejected(() -> resultSet.getDouble(1));
assertTimeColumnRejected(() -> resultSet.getDate(1));

// Reading by name goes through the same path.
assertTimeColumnRejected(() -> resultSet.getInt("Time"));
}
}

@FunctionalInterface
private interface ResultSetRead {
void run() throws SQLException;
}

private void assertTimeColumnRejected(ResultSetRead read) {
try {
read.run();
Assert.fail("reading the time column with a strictly-typed getter should have thrown");
} catch (SQLException e) {
// expected
} catch (RuntimeException e) {
Assert.fail(
"expected a SQLException but the time column leaked an unchecked "
+ e.getClass().getName()
+ ": "
+ e.getMessage());
}
}

/** Same tree-model fixture as testQuery: column 1 is Time, columns 2..5 are measurements. */
private ResultSet executeAndFetchTreeModelResultSet() throws Exception {
List<String> columns = new ArrayList<>();
columns.add("root.vehicle.d0.s2");
columns.add("root.vehicle.d0.s1");
columns.add("root.vehicle.d0.s0");
columns.add("root.vehicle.d0.s2");

List<String> dataTypeList = new ArrayList<>();
dataTypeList.add("FLOAT");
dataTypeList.add("INT64");
dataTypeList.add("INT32");
dataTypeList.add("FLOAT");

when(execResp.isSetColumns()).thenReturn(true);
when(execResp.getColumns()).thenReturn(columns);
when(execResp.isSetDataTypeList()).thenReturn(true);
when(execResp.getDataTypeList()).thenReturn(dataTypeList);
when(execResp.isSetOperationType()).thenReturn(true);
when(execResp.getOperationType()).thenReturn("QUERY");
when(execResp.isSetQueryId()).thenReturn(true);
when(execResp.getQueryId()).thenReturn(queryId);
when(execResp.isSetTableModel()).thenReturn(false);
when(execResp.isIgnoreTimeStamp()).thenReturn(false);

List<Integer> columnIndex2TsBlockColumnIndexList = new ArrayList<>(columns.size());
columnIndex2TsBlockColumnIndexList.add(0);
columnIndex2TsBlockColumnIndexList.add(1);
columnIndex2TsBlockColumnIndexList.add(2);
columnIndex2TsBlockColumnIndexList.add(0);
when(execResp.getColumnIndex2TsBlockColumnIndexList())
.thenReturn(columnIndex2TsBlockColumnIndexList);

Assert.assertTrue(statement.execute("select * from root.vehicle.d0"));
fetchResultsResp.hasResultSet = true;
return statement.getResultSet();
}

private void constructObjectList(List<Object> standardObject) {
Object[][] input = {
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ public final class RpcMessages {
"column index %d out of range %d";
public static final String UNKNOWN_COLUMN_NAME = "Unknown column name: ";
public static final String NO_RECORD_REMAINS = "No record remains";
public static final String CANNOT_READ_BOOLEAN_FROM_TIME_COLUMN =
"Cannot read boolean from time column";
public static final String CANNOT_READ_DOUBLE_FROM_TIME_COLUMN =
"Cannot read double from time column";
public static final String CANNOT_READ_FLOAT_FROM_TIME_COLUMN =
"Cannot read float from time column";
public static final String CANNOT_READ_INT32_FROM_TIME_COLUMN =
"Cannot read int32 from time column";
public static final String CANNOT_READ_BINARY_FROM_TIME_COLUMN =
"Cannot read binary from time column";
public static final String CANNOT_CLOSE_DATASET =
"Cannot close dataset, because of network connection: {} ";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ public final class RpcMessages {
public static final String COLUMN_INDEX_OUT_OF_RANGE = "列索引 %d 超出范围 %d";
public static final String UNKNOWN_COLUMN_NAME = "未知列名:";
public static final String NO_RECORD_REMAINS = "没有剩余记录";
public static final String CANNOT_READ_BOOLEAN_FROM_TIME_COLUMN = "无法从时间列读取 boolean 值";
public static final String CANNOT_READ_DOUBLE_FROM_TIME_COLUMN = "无法从时间列读取 double 值";
public static final String CANNOT_READ_FLOAT_FROM_TIME_COLUMN = "无法从时间列读取 float 值";
public static final String CANNOT_READ_INT32_FROM_TIME_COLUMN = "无法从时间列读取 int32 值";
public static final String CANNOT_READ_BINARY_FROM_TIME_COLUMN = "无法从时间列读取 binary 值";
public static final String CANNOT_CLOSE_DATASET = "无法关闭数据集,网络连接异常:{} ";

// RpcUtils
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,16 @@ public boolean getBoolean(String columnName) throws StatementExecutionException
return getBooleanByTsBlockColumnIndex(getTsBlockColumnIndexForColumnName(columnName));
}

// A negative tsBlockColumnIndex denotes the tree-model time pseudo-column. Only getLong,
// getString and getObject can serve it; the strictly-typed getters reject it here so that
// callers see a StatementExecutionException instead of an ArrayIndexOutOfBoundsException
// escaping from TsBlock.getColumn(-1).
private boolean getBooleanByTsBlockColumnIndex(int tsBlockColumnIndex)
throws StatementExecutionException {
checkRecord();
if (tsBlockColumnIndex < 0) {
throw new StatementExecutionException(RpcMessages.CANNOT_READ_BOOLEAN_FROM_TIME_COLUMN);
}
if (!isNull(tsBlockColumnIndex, tsBlockIndex)) {
lastReadWasNull = false;
return curTsBlock.getColumn(tsBlockColumnIndex).getBoolean(tsBlockIndex);
Expand All @@ -353,6 +360,9 @@ public double getDouble(String columnName) throws StatementExecutionException {
private double getDoubleByTsBlockColumnIndex(int tsBlockColumnIndex)
throws StatementExecutionException {
checkRecord();
if (tsBlockColumnIndex < 0) {
throw new StatementExecutionException(RpcMessages.CANNOT_READ_DOUBLE_FROM_TIME_COLUMN);
}
if (!isNull(tsBlockColumnIndex, tsBlockIndex)) {
lastReadWasNull = false;
return curTsBlock.getColumn(tsBlockColumnIndex).getDouble(tsBlockIndex);
Expand All @@ -373,6 +383,9 @@ public float getFloat(String columnName) throws StatementExecutionException {
private float getFloatByTsBlockColumnIndex(int tsBlockColumnIndex)
throws StatementExecutionException {
checkRecord();
if (tsBlockColumnIndex < 0) {
throw new StatementExecutionException(RpcMessages.CANNOT_READ_FLOAT_FROM_TIME_COLUMN);
}
if (!isNull(tsBlockColumnIndex, tsBlockIndex)) {
lastReadWasNull = false;
return curTsBlock.getColumn(tsBlockColumnIndex).getFloat(tsBlockIndex);
Expand All @@ -393,6 +406,9 @@ public int getInt(String columnName) throws StatementExecutionException {
private int getIntByTsBlockColumnIndex(int tsBlockColumnIndex)
throws StatementExecutionException {
checkRecord();
if (tsBlockColumnIndex < 0) {
throw new StatementExecutionException(RpcMessages.CANNOT_READ_INT32_FROM_TIME_COLUMN);
}
if (!isNull(tsBlockColumnIndex, tsBlockIndex)) {
lastReadWasNull = false;
TSDataType type = curTsBlock.getColumn(tsBlockColumnIndex).getDataType();
Expand Down Expand Up @@ -451,6 +467,9 @@ public Binary getBinary(String columnName) throws StatementExecutionException {
private Binary getBinaryTsBlockColumnIndex(int tsBlockColumnIndex)
throws StatementExecutionException {
checkRecord();
if (tsBlockColumnIndex < 0) {
throw new StatementExecutionException(RpcMessages.CANNOT_READ_BINARY_FROM_TIME_COLUMN);
}
if (!isNull(tsBlockColumnIndex, tsBlockIndex)) {
lastReadWasNull = false;
return curTsBlock.getColumn(tsBlockColumnIndex).getBinary(tsBlockIndex);
Expand Down