未验证 提交 8433cab9 编写于 作者: H huolibo 提交者: GitHub

[TD-13836]<fix>: fix jdbc parse fetchblock data errors (#10726)

* [TD-13836]<fix>: fix jdbc parse fetchblock data errors

* [TD-13836]<fix>: format convert

* [TD-13836]<fix> : fix NPE exception

* [TD-13836]<fix>: Uniform getTimeStamp API

* [TD-13836]<fix>: number value  return 0 when it's none

* [TD-13836]<fix>: fix related test cases
上级 1d0a9831
......@@ -19,7 +19,6 @@ import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.ArrayList;
import java.util.Calendar;
......@@ -53,7 +52,7 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
return rowData;
}
public TSDBResultSet(TSDBStatement statement, TSDBJNIConnector connector, long resultSetPointer) throws SQLException {
public TSDBResultSet(TSDBStatement statement, TSDBJNIConnector connector, long resultSetPointer, int timestampPrecision) throws SQLException {
this.statement = statement;
this.jniConnector = connector;
this.resultSetPointer = resultSetPointer;
......@@ -69,7 +68,8 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
}
this.rowData = new TSDBResultSetRowData(this.columnMetaDataList.size());
this.blockData = new TSDBResultSetBlockData(this.columnMetaDataList, this.columnMetaDataList.size());
this.blockData = new TSDBResultSetBlockData(this.columnMetaDataList, this.columnMetaDataList.size(), timestampPrecision);
this.timestampPrecision = timestampPrecision;
}
public boolean next() throws SQLException {
......@@ -268,7 +268,7 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
checkAvailability(columnIndex, this.columnMetaDataList.size());
if (this.getBatchFetch())
return this.blockData.getString(columnIndex).getBytes();
return this.blockData.getBytes(columnIndex -1);
Object value = this.rowData.getObject(columnIndex);
this.lastWasNull = value == null;
......@@ -343,7 +343,7 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
@Override
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
if (this.getBatchFetch())
return new BigDecimal(this.blockData.getLong(columnIndex - 1));
return BigDecimal.valueOf(this.blockData.getDouble(columnIndex - 1));
this.lastWasNull = this.rowData.wasNull(columnIndex);
if (lastWasNull)
......
......@@ -25,10 +25,15 @@ import java.nio.ShortBuffer;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import com.taosdata.jdbc.enums.TimestampPrecision;
import com.taosdata.jdbc.utils.NullType;
public class TSDBResultSetBlockData {
......@@ -39,9 +44,12 @@ public class TSDBResultSetBlockData {
private List<ColumnMetaData> columnMetaDataList;
private ArrayList<Object> colData;
public TSDBResultSetBlockData(List<ColumnMetaData> colMeta, int numOfCols) {
private int timestampPrecision;
public TSDBResultSetBlockData(List<ColumnMetaData> colMeta, int numOfCols, int timestampPrecision) {
this.columnMetaDataList = colMeta;
this.colData = new ArrayList<>(numOfCols);
this.timestampPrecision = timestampPrecision;
}
public TSDBResultSetBlockData() {
......@@ -169,12 +177,46 @@ public class TSDBResultSetBlockData {
public String getString(int col) throws SQLException {
Object obj = get(col);
if (obj == null) {
return new NullType().toString();
// return new NullType().toString();
return null;
}
if (obj instanceof String)
return (String) obj;
if (obj instanceof byte[]) {
String charset = TaosGlobalConfig.getCharset();
try {
return new String((byte[]) obj, charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage());
}
}
return obj.toString();
}
public byte[] getBytes(int col) throws SQLException {
Object obj = get(col);
if (obj == null) {
return null;
}
if (obj instanceof byte[])
return (byte[]) obj;
if (obj instanceof String)
return ((String) obj).getBytes();
if (obj instanceof Long)
return Longs.toByteArray((long) obj);
if (obj instanceof Integer)
return Ints.toByteArray((int) obj);
if (obj instanceof Short)
return Shorts.toByteArray((short) obj);
if (obj instanceof Byte)
return new byte[]{(byte) obj};
return obj.toString().getBytes();
}
public int getInt(int col) {
Object obj = get(col);
if (obj == null) {
......@@ -184,14 +226,18 @@ public class TSDBResultSetBlockData {
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return (boolean) obj ? 1 : 0;
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
return (byte) obj;
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
return (short) obj;
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return (int) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return ((Long) obj).intValue();
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return ((Long) ((Timestamp) obj).getTime()).intValue();
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
......@@ -218,19 +264,25 @@ public class TSDBResultSetBlockData {
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return (boolean) obj;
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
return ((byte) obj == 0) ? Boolean.FALSE : Boolean.TRUE;
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
return ((short) obj == 0) ? Boolean.FALSE : Boolean.TRUE;
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return ((int) obj == 0L) ? Boolean.FALSE : Boolean.TRUE;
return ((int) obj == 0) ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
return (((long) obj) == 0L) ? Boolean.FALSE : Boolean.TRUE;
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return (((Long) obj) == 0L) ? Boolean.FALSE : Boolean.TRUE;
return ((Timestamp) obj).getTime() == 0L ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return (((float) obj) == 0f) ? Boolean.FALSE : Boolean.TRUE;
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return (((Double) obj) == 0) ? Boolean.FALSE : Boolean.TRUE;
return (((double) obj) == 0) ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
......@@ -258,17 +310,31 @@ public class TSDBResultSetBlockData {
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return (boolean) obj ? 1 : 0;
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
return (byte) obj;
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
return (short) obj;
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return (int) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return (long) obj;
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
Timestamp ts = (Timestamp) obj;
switch (this.timestampPrecision) {
case TimestampPrecision.MS:
default:
return ts.getTime();
case TimestampPrecision.US:
return ts.getTime() * 1000 + ts.getNanos() / 1000 % 1000;
case TimestampPrecision.NS:
return ts.getTime() * 1000_000 + ts.getNanos() % 1000_000;
}
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return ((Float) obj).longValue();
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return ((Double) obj).longValue();
}
......@@ -284,6 +350,17 @@ public class TSDBResultSetBlockData {
}
public Timestamp getTimestamp(int col) throws SQLException {
Object obj = get(col);
if (obj == null) {
return null;
}
int type = this.columnMetaDataList.get(col).getColType();
if (type == TSDBConstants.TSDB_DATA_TYPE_BIGINT)
return parseTimestampColumnData((long) obj);
if (type == TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP)
return (Timestamp) obj;
return new Timestamp(getLong(col));
}
......@@ -296,17 +373,31 @@ public class TSDBResultSetBlockData {
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return (boolean) obj ? 1 : 0;
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
return (byte) obj;
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
return (short) obj;
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return (int) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return (long) obj;
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
Timestamp ts = (Timestamp) obj;
switch (this.timestampPrecision) {
case TimestampPrecision.MS:
default:
return ts.getTime();
case TimestampPrecision.US:
return ts.getTime() * 1000 + ts.getNanos() / 1000 % 1000;
case TimestampPrecision.NS:
return ts.getTime() * 1000_000 + ts.getNanos() % 1000_000;
}
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return Double.parseDouble(String.valueOf(obj));
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return (double) obj;
}
......@@ -367,7 +458,15 @@ public class TSDBResultSetBlockData {
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
LongBuffer lb = (LongBuffer) this.colData.get(col);
long val = lb.get(this.rowIndex);
if (NullType.isBigIntNull(val)) {
return null;
}
return parseTimestampColumnData(val);
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: {
LongBuffer lb = (LongBuffer) this.colData.get(col);
long val = lb.get(this.rowIndex);
......@@ -408,7 +507,7 @@ public class TSDBResultSetBlockData {
return null;
}
return new String(dest);
return dest;
}
case TSDBConstants.TSDB_DATA_TYPE_JSON:
......@@ -432,4 +531,21 @@ public class TSDBResultSetBlockData {
return 0;
}
private Timestamp parseTimestampColumnData(long value) {
if (TimestampPrecision.MS == timestampPrecision)
return new Timestamp(value);
if (TimestampPrecision.US == timestampPrecision) {
long epochSec = value / 1000_000L;
long nanoAdjustment = value % 1000_000L * 1000L;
return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
}
if (TimestampPrecision.NS == timestampPrecision) {
long epochSec = value / 1000_000_000L;
long nanoAdjustment = value % 1000_000_000L;
return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
}
return null;
}
}
......@@ -14,8 +14,6 @@
*****************************************************************************/
package com.taosdata.jdbc;
import com.taosdata.jdbc.utils.NullType;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.sql.SQLException;
......@@ -132,7 +130,7 @@ public class TSDBResultSetRowData {
public int getInt(int col, int nativeType) throws SQLException {
Object obj = data.get(col - 1);
if (obj == null)
return NullType.getIntNull();
return 0;
switch (nativeType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
......@@ -213,7 +211,7 @@ public class TSDBResultSetRowData {
public long getLong(int col, int nativeType) throws SQLException {
Object obj = data.get(col - 1);
if (obj == null) {
return NullType.getBigIntNull();
return 0;
}
switch (nativeType) {
......@@ -282,7 +280,7 @@ public class TSDBResultSetRowData {
public float getFloat(int col, int nativeType) {
Object obj = data.get(col - 1);
if (obj == null)
return NullType.getFloatNull();
return 0;
switch (nativeType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
......@@ -301,7 +299,7 @@ public class TSDBResultSetRowData {
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
return (Long) obj;
default:
return NullType.getFloatNull();
return 0;
}
}
......@@ -322,7 +320,7 @@ public class TSDBResultSetRowData {
public double getDouble(int col, int nativeType) {
Object obj = data.get(col - 1);
if (obj == null)
return NullType.getDoubleNull();
return 0;
switch (nativeType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
......@@ -341,7 +339,7 @@ public class TSDBResultSetRowData {
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
return (Long) obj;
default:
return NullType.getDoubleNull();
return 0;
}
}
......@@ -454,7 +452,7 @@ public class TSDBResultSetRowData {
milliseconds = ts / 1_000;
fracNanoseconds = (int) (ts * 1_000 % 1_000_000_000);
if (fracNanoseconds < 0) {
if (milliseconds == 0 ){
if (milliseconds == 0) {
milliseconds = -1;
}
fracNanoseconds += 1_000_000_000;
......@@ -465,7 +463,7 @@ public class TSDBResultSetRowData {
milliseconds = ts / 1_000_000;
fracNanoseconds = (int) (ts % 1_000_000_000);
if (fracNanoseconds < 0) {
if (milliseconds == 0 ){
if (milliseconds == 0) {
milliseconds = -1;
}
fracNanoseconds += 1_000_000_000;
......
......@@ -46,9 +46,8 @@ public class TSDBStatement extends AbstractStatement {
this.connection.getConnector().freeResultSet(pSql);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
}
TSDBResultSet res = new TSDBResultSet(this, this.connection.getConnector(), pSql);
int timestampPrecision = this.connection.getConnector().getResultTimePrecision(pSql);
res.setTimestampPrecision(timestampPrecision);
TSDBResultSet res = new TSDBResultSet(this, this.connection.getConnector(), pSql, timestampPrecision);
res.setBatchFetch(this.connection.getBatchFetch());
return res;
}
......@@ -91,7 +90,8 @@ public class TSDBStatement extends AbstractStatement {
return false;
}
this.resultSet = new TSDBResultSet(this, this.connection.getConnector(), pSql);
int timestampPrecision = this.connection.getConnector().getResultTimePrecision(pSql);
this.resultSet = new TSDBResultSet(this, this.connection.getConnector(), pSql, timestampPrecision);
this.resultSet.setBatchFetch(this.connection.getBatchFetch());
return true;
}
......
......@@ -14,6 +14,8 @@
*****************************************************************************/
package com.taosdata.jdbc;
import com.taosdata.jdbc.enums.TimestampPrecision;
import java.sql.SQLException;
public class TSDBSubscribe {
......@@ -41,7 +43,7 @@ public class TSDBSubscribe {
} else if (resultSetPointer == TSDBConstants.JNI_NULL_POINTER) {
return null;
} else {
return new TSDBResultSet(null, this.connecter, resultSetPointer);
return new TSDBResultSet(null, this.connecter, resultSetPointer, TimestampPrecision.UNKNOWN);
}
}
......
......@@ -4,4 +4,5 @@ public class TimestampPrecision {
public static final int MS = 0;
public static final int US = 1;
public static final int NS = 2;
public static final int UNKNOWN = 9999;
}
......@@ -482,9 +482,6 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
return Shorts.toByteArray((short) value);
if (value instanceof Byte)
return new byte[]{(byte) value};
if (value instanceof Timestamp) {
return Utils.formatTimestamp((Timestamp) value).getBytes();
}
return value.toString().getBytes();
}
......
......@@ -645,8 +645,6 @@ public class BlockResultSet extends AbstractWSResultSet {
}
if (value instanceof Float)
return (float) value;
if (value instanceof Double)
return (float) (double) value;
int taosType = fields.get(columnIndex - 1).getTaosType();
switch (taosType) {
......@@ -670,6 +668,12 @@ public class BlockResultSet extends AbstractWSResultSet {
throwRangeException(value.toString(), columnIndex, Types.FLOAT);
return tmp.floatValue();
}
case TSDB_DATA_TYPE_DOUBLE:{
Double tmp = (double) value;
if (tmp < Float.MIN_VALUE || tmp > Float.MAX_VALUE)
throwRangeException(value.toString(), columnIndex, Types.FLOAT);
return Float.parseFloat(String.valueOf(tmp));
}
case TSDB_DATA_TYPE_NCHAR:
case TSDB_DATA_TYPE_JSON:
......@@ -700,7 +704,7 @@ public class BlockResultSet extends AbstractWSResultSet {
if (value instanceof Double)
return (double) value;
if (value instanceof Float)
return (float) value;
return Double.parseDouble(String.valueOf(value));
int taosType = fields.get(columnIndex - 1).getTaosType();
switch (taosType) {
......@@ -763,9 +767,6 @@ public class BlockResultSet extends AbstractWSResultSet {
return Shorts.toByteArray((short) value);
if (value instanceof Byte)
return new byte[]{(byte) value};
if (value instanceof Timestamp) {
return Utils.formatTimestamp((Timestamp) value).getBytes();
}
return value.toString().getBytes();
}
......
......@@ -9,7 +9,9 @@ import org.junit.runners.MethodSorters;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@RunWith(CatalogRunner.class)
......@@ -1129,14 +1131,14 @@ public class JsonTagTest {
ResultSet resultSet = statement.executeQuery("select stddev(dataint) from jsons1 group by jtag->'tag1'");
String s = "";
int count = 0;
Set<String> set = new HashSet<>();
while (resultSet.next()) {
count++;
s = resultSet.getString(2);
set.add(resultSet.getString(2));
}
Assert.assertEquals(8, count);
Assert.assertEquals("\"收到货\"", s);
close(resultSet);
Assert.assertTrue(set.contains("\"femail\""));
Assert.assertTrue(set.contains("\"收到货\""));
}
@Test
......
......@@ -727,8 +727,8 @@ public class TSDBDatabaseMetaDataTest {
Assert.assertEquals(26, columns.getInt("COLUMN_SIZE"));
// DECIMAL_DIGITS
Assert.assertEquals("DECIMAL_DIGITS", meta.getColumnLabel(9));
Assert.assertEquals(Integer.MIN_VALUE, columns.getInt(9));
Assert.assertEquals(Integer.MIN_VALUE, columns.getInt("DECIMAL_DIGITS"));
Assert.assertEquals(0, columns.getInt(9));
Assert.assertEquals(0, columns.getInt("DECIMAL_DIGITS"));
Assert.assertEquals(null, columns.getString(9));
Assert.assertEquals(null, columns.getString("DECIMAL_DIGITS"));
// NUM_PREC_RADIX
......@@ -773,8 +773,8 @@ public class TSDBDatabaseMetaDataTest {
Assert.assertEquals(12, columns.getInt("COLUMN_SIZE"));
// DECIMAL_DIGITS
Assert.assertEquals("DECIMAL_DIGITS", meta.getColumnLabel(9));
Assert.assertEquals(Integer.MIN_VALUE, columns.getInt(9));
Assert.assertEquals(Integer.MIN_VALUE, columns.getInt("DECIMAL_DIGITS"));
Assert.assertEquals(0, columns.getInt(9));
Assert.assertEquals(0, columns.getInt("DECIMAL_DIGITS"));
Assert.assertEquals(null, columns.getString(9));
Assert.assertEquals(null, columns.getString("DECIMAL_DIGITS"));
// NUM_PREC_RADIX
......
......@@ -732,8 +732,8 @@ public class RestfulDatabaseMetaDataTest {
Assert.assertEquals(26, columns.getInt("COLUMN_SIZE"));
// DECIMAL_DIGITS
Assert.assertEquals("DECIMAL_DIGITS", meta.getColumnLabel(9));
Assert.assertEquals(Integer.MIN_VALUE, columns.getInt(9));
Assert.assertEquals(Integer.MIN_VALUE, columns.getInt("DECIMAL_DIGITS"));
Assert.assertEquals(0, columns.getInt(9));
Assert.assertEquals(0, columns.getInt("DECIMAL_DIGITS"));
Assert.assertEquals(null, columns.getString(9));
Assert.assertEquals(null, columns.getString("DECIMAL_DIGITS"));
// NUM_PREC_RADIX
......@@ -778,8 +778,8 @@ public class RestfulDatabaseMetaDataTest {
Assert.assertEquals(12, columns.getInt("COLUMN_SIZE"));
// DECIMAL_DIGITS
Assert.assertEquals("DECIMAL_DIGITS", meta.getColumnLabel(9));
Assert.assertEquals(Integer.MIN_VALUE, columns.getInt(9));
Assert.assertEquals(Integer.MIN_VALUE, columns.getInt("DECIMAL_DIGITS"));
Assert.assertEquals(0, columns.getInt(9));
Assert.assertEquals(0, columns.getInt("DECIMAL_DIGITS"));
Assert.assertEquals(null, columns.getString(9));
Assert.assertEquals(null, columns.getString("DECIMAL_DIGITS"));
// NUM_PREC_RADIX
......
......@@ -8,6 +8,8 @@ import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import java.sql.*;
import java.util.HashSet;
import java.util.Set;
/**
* Most of the functionality is consistent with {@link com.taosdata.jdbc.JsonTagTest},
......@@ -1143,13 +1145,14 @@ public class RestfulJsonTagTest {
ResultSet resultSet = statement.executeQuery("select stddev(dataint) from jsons1 group by jtag->'tag1'");
String s = "";
int count = 0;
Set<String> set = new HashSet<>();
while (resultSet.next()) {
count++;
s = resultSet.getString(2);
set.add(resultSet.getString(2));
}
Assert.assertEquals(8, count);
Assert.assertEquals("\"收到货\"", s);
Assert.assertTrue(set.contains("\"femail\""));
Assert.assertTrue(set.contains("\"收到货\""));
close(resultSet);
}
......
......@@ -133,7 +133,7 @@ public class RestfulResultSetTest {
@Test
public void getBytes() throws SQLException {
byte[] f1 = rs.getBytes("f1");
Assert.assertEquals("2021-01-01 00:00:00.000", new String(f1));
Assert.assertEquals("2021-01-01 00:00:00.0", new String(f1));
byte[] f2 = rs.getBytes("f2");
Assert.assertEquals(1, Ints.fromByteArray(f2));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册