From 5f7662ebd680404bc33e14751f96c87abada5ad5 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Fri, 25 Oct 2024 15:36:06 +0800 Subject: [PATCH 01/15] add stmt2 --- .../com/taosdata/jdbc/common/TableInfo.java | 43 +++++ .../com/taosdata/jdbc/common/TagInfo.java | 38 ++++ .../jdbc/ws/TSWSPreparedStatement.java | 163 +++++------------- .../com/taosdata/jdbc/ws/entity/Action.java | 9 + .../jdbc/ws/stmt2/entity/BindReq.java | 29 ++++ .../jdbc/ws/stmt2/entity/CloseReq.java | 20 +++ .../jdbc/ws/stmt2/entity/ExecReq.java | 20 +++ .../jdbc/ws/stmt2/entity/ExecResp.java | 28 +++ .../taosdata/jdbc/ws/stmt2/entity/Field.java | 62 +++++++ .../jdbc/ws/stmt2/entity/InitReq.java | 27 +++ .../jdbc/ws/stmt2/entity/PrepareReq.java | 39 +++++ .../jdbc/ws/stmt2/entity/PrepareResp.java | 50 ++++++ .../jdbc/ws/stmt2/entity/RequestFactory.java | 52 ++++++ .../jdbc/ws/stmt2/entity/Stmt2Resp.java | 23 +++ 14 files changed, 481 insertions(+), 122 deletions(-) create mode 100644 src/main/java/com/taosdata/jdbc/common/TableInfo.java create mode 100644 src/main/java/com/taosdata/jdbc/common/TagInfo.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/BindReq.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/CloseReq.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecReq.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecResp.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/InitReq.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareReq.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareResp.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/RequestFactory.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java diff --git a/src/main/java/com/taosdata/jdbc/common/TableInfo.java b/src/main/java/com/taosdata/jdbc/common/TableInfo.java new file mode 100644 index 00000000..3314492f --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/common/TableInfo.java @@ -0,0 +1,43 @@ +package com.taosdata.jdbc.common; + +import java.util.ArrayList; +import java.util.List; + +public class TableInfo { + private List dataList = new ArrayList<>(); + + private final String tableName; + private final List; + // taos data type + private final int type; + private final int index; + + public TableInfo(int columnIndex, Object data, int type) { + this.index = columnIndex; + this.dataList.add(data); + this.type = type; + } + + public TableInfo(int columnIndex, List dataList, int type, Integer flag) { + this.index = columnIndex; + this.dataList = dataList; + this.type = type; + } + + public void add(Object data) { + this.dataList.add(data); + } + + public List getDataList() { + return dataList; + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + +} diff --git a/src/main/java/com/taosdata/jdbc/common/TagInfo.java b/src/main/java/com/taosdata/jdbc/common/TagInfo.java new file mode 100644 index 00000000..6c4fa0f3 --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/common/TagInfo.java @@ -0,0 +1,38 @@ +package com.taosdata.jdbc.common; + +import java.util.ArrayList; +import java.util.List; + +public class TagInfo implements Comparable { + private Object data; + // taos data type + private final int type; + private final int index; + + public TagInfo(int index, Object data, int type) { + this.index = index; + this.data = data; + this.type = type; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + + @Override + public int compareTo(TagInfo c) { + return this.index > c.index ? 1 : -1; + } +} diff --git a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java index 45dd13ef..f4307586 100644 --- a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java +++ b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java @@ -4,7 +4,6 @@ import com.taosdata.jdbc.common.ColumnInfo; import com.taosdata.jdbc.common.SerializeBlock; import com.taosdata.jdbc.enums.BindType; -import com.taosdata.jdbc.enums.DataType; import com.taosdata.jdbc.enums.TimestampPrecision; import com.taosdata.jdbc.rs.ConnectionParam; import com.taosdata.jdbc.utils.ReqId; @@ -13,10 +12,7 @@ import com.taosdata.jdbc.ws.entity.Code; import com.taosdata.jdbc.ws.entity.Request; import com.taosdata.jdbc.ws.entity.Response; -import com.taosdata.jdbc.ws.stmt.entity.ExecResp; -import com.taosdata.jdbc.ws.stmt.entity.GetColFieldsResp; -import com.taosdata.jdbc.ws.stmt.entity.RequestFactory; -import com.taosdata.jdbc.ws.stmt.entity.StmtResp; +import com.taosdata.jdbc.ws.stmt2.entity.*; import java.io.IOException; import java.io.InputStream; @@ -29,7 +25,6 @@ import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -38,9 +33,6 @@ import static com.taosdata.jdbc.utils.SqlSyntaxValidator.isUseSql; public class TSWSPreparedStatement extends WSStatement implements PreparedStatement { - public static final Pattern INSERT_PATTERN = Pattern.compile( - "insert\\s+into\\s+([.\\w]+|\\?)\\s+(using\\s+([.\\w]+)(\\s*\\(.*\\)\\s*|\\s+)tags\\s*\\(.*\\))?\\s*(\\(.*\\))?\\s*values\\s*\\(.*\\)" - ); private final ConnectionParam param; private long reqId; private long stmtId; @@ -48,9 +40,11 @@ public class TSWSPreparedStatement extends WSStatement implements PreparedStatem private int queryTimeout = 0; private int precision = TimestampPrecision.MS; + private int toBeBindColCount = 0; + private List fields; + private boolean isInsert = false; + - private String insertDbName; - static private Map precisionHashMap = new ConcurrentHashMap(); private final Map column = new HashMap<>(); private final Map tag = new HashMap<>(); @@ -58,71 +52,54 @@ public class TSWSPreparedStatement extends WSStatement implements PreparedStatem private final PriorityQueue queue = new PriorityQueue<>(); + private final + public TSWSPreparedStatement(Transport transport, ConnectionParam param, String database, AbstractConnection connection, String sql, Long instanceId) throws SQLException { super(transport, database, connection, instanceId); this.rawSql = sql; this.param = param; - this.insertDbName = database; if (!sql.contains("?")) return; - String useDb = null; - Matcher matcher = INSERT_PATTERN.matcher(sql); - if (matcher.find()) { - if (matcher.group(1).equals("?") && matcher.group(3) != null) { - String usingGroup = matcher.group(3); - if (usingGroup.contains(".")) { - String[] split = usingGroup.split("\\."); - useDb = split[0]; - } - } else { - String usingGroup = matcher.group(1); - if (usingGroup.contains(".")) { - String[] split = usingGroup.split("\\."); - useDb = split[0]; - } - } - - if (useDb == null && database != null) { - useDb = database; - } - if (useDb != null) { - insertDbName = useDb; - Integer precisionObj = precisionHashMap.get(useDb); - if (precisionObj != null){ - precision = precisionObj; - } else { - updatePrecision(useDb); - } - - - } - } - - reqId = ReqId.getReqID(); - Request request = RequestFactory.generateInit(reqId); - StmtResp resp = (StmtResp) transport.send(request); + Request request = RequestFactory.generateInit(reqId, true, false); + Stmt2Resp resp = (Stmt2Resp) transport.send(request); if (Code.SUCCESS.getCode() != resp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); } stmtId = resp.getStmtId(); Request prepare = RequestFactory.generatePrepare(stmtId, reqId, sql); - StmtResp prepareResp = (StmtResp) transport.send(prepare); + PrepareResp prepareResp = (PrepareResp) transport.send(prepare); if (Code.SUCCESS.getCode() != prepareResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(prepareResp.getCode()) + "):" + prepareResp.getMessage()); } - } - private void updatePrecision(String database) throws SQLException{ - try (ResultSet resultSet = this.executeQuery("select `precision` from information_schema.ins_databases where name = '" + database + "'")) { - while (resultSet.next()) { - String tmp = resultSet.getString(1); - precision = TimestampPrecision.getPrecision(tmp); - precisionHashMap.put(database, precision); - } + if (prepareResp.getFieldsCount() != prepareResp.getFields().size()){ + throw new SQLException("prepare error: fields count not match"); + } + + isInsert = prepareResp.isInsert(); + if (prepareResp.getFieldsCount() > 0){ + toBeBindColCount = prepareResp.getFieldsCount(); + fields = prepareResp.getFields(); + } else{ + return; + } + + // now we know the number of fields, we can prepare the cache data + if (prepareResp.isInsert()){ +// for (int i = 0; i < toBeBindColCount; i++){ +// if (prepareResp.getFields().get(i).getType() == TSDB_DATA_TYPE_UNKNOWN){ +// column.put(i, new Column(null, TSDB_DATA_TYPE_UNKNOWN, i)); +// } +// column.put(i, new Column(null, TSDB_DATA_TYPE_UNKNOWN, i)); +// } + + } else { + } } + @Override public int getQueryTimeout() throws SQLException { return queryTimeout; @@ -139,42 +116,8 @@ public void setQueryTimeout(int seconds) throws SQLException { transport.setTimeout(seconds * 1000L); } - private void checkUseStatement(String sql) throws SQLException { - if (sql == null || sql.isEmpty()) { - throw new SQLException("sql is empty"); - } - - if (isUseSql(sql)) { - String database = getDatabaseName(sql); - if (null != database) { - WSConnection.reInitTransport(transport, param, database); - - try (ResultSet resultSet = this.executeQuery("select `precision` from information_schema.ins_databases where name = '" + database + "'")) { - while (resultSet.next()) { - String tmp = resultSet.getString(1); - precision = TimestampPrecision.getPrecision(tmp); - } - } - - reqId = ReqId.getReqID(); - Request request = RequestFactory.generateInit(reqId); - StmtResp resp = (StmtResp) transport.send(request); - if (Code.SUCCESS.getCode() != resp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); - } - stmtId = resp.getStmtId(); - Request prepare = RequestFactory.generatePrepare(stmtId, reqId, rawSql); - StmtResp prepareResp = (StmtResp) transport.send(prepare); - if (Code.SUCCESS.getCode() != prepareResp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(prepareResp.getCode()) + "):" + prepareResp.getMessage()); - } - } - } - } - @Override public boolean execute(String sql, Long reqId) throws SQLException { - checkUseStatement(sql); return super.execute(sql, reqId); } @@ -219,7 +162,7 @@ public int executeUpdate() throws SQLException { } catch (IOException e) { throw new SQLException("data serialize error!", e); } - StmtResp bindResp = (StmtResp) transport.send(Action.SET_TAGS.getAction(), + Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.SET_TAGS.getAction(), reqId, stmtId, BindType.TAG.get(), tagBlock); if (Code.SUCCESS.getCode() != bindResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); @@ -236,26 +179,16 @@ public int executeUpdate() throws SQLException { } catch (IOException e) { throw new SQLException("data serialize error!", e); } - StmtResp bindResp = (StmtResp) transport.send(Action.BIND.getAction(), + Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.BIND.getAction(), reqId, stmtId, BindType.BIND.get(), rawBlock); if (Code.SUCCESS.getCode() != bindResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); } - // add batch - Request batch = RequestFactory.generateBatch(stmtId, reqId); - Response send = transport.send(batch); - StmtResp batchResp = (StmtResp) send; - if (Code.SUCCESS.getCode() != batchResp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(batchResp.getCode()) + "):" + batchResp.getMessage()); - } this.clearParameters(); // send Request request = RequestFactory.generateExec(stmtId, reqId); ExecResp resp = (ExecResp) transport.send(request); if (Code.SUCCESS.getCode() != resp.getCode()) { - if (TIMESTAMP_DATA_OUT_OF_RANGE == resp.getCode()){ - updatePrecision(insertDbName); - } throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage(), "P0001", resp.getCode()); } @@ -265,7 +198,7 @@ public int executeUpdate() throws SQLException { // set sub-table name public void setTableName(String name) throws SQLException { Request request = RequestFactory.generateSetTableName(stmtId, reqId, name); - StmtResp resp = (StmtResp) transport.send(request); + Stmt2Resp resp = (Stmt2Resp) transport.send(request); if (Code.SUCCESS.getCode() != resp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); } @@ -728,7 +661,7 @@ public int[] executeBatch() throws SQLException { } catch (IOException e) { throw new SQLException("data serialize error!", e); } - StmtResp bindResp = (StmtResp) transport.send(Action.SET_TAGS.getAction(), + Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.SET_TAGS.getAction(), reqId, stmtId, BindType.TAG.get(), tagBlock); if (Code.SUCCESS.getCode() != bindResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); @@ -741,18 +674,11 @@ public int[] executeBatch() throws SQLException { } catch (IOException e) { throw new SQLException("data serialize error!", e); } - StmtResp bindResp = (StmtResp) transport.send(Action.BIND.getAction(), + Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.BIND.getAction(), reqId, stmtId, BindType.BIND.get(), rawBlock); if (Code.SUCCESS.getCode() != bindResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); } - // add batch - Request batch = RequestFactory.generateBatch(stmtId, reqId); - Response send = transport.send(batch); - StmtResp batchResp = (StmtResp) send; - if (Code.SUCCESS.getCode() != batchResp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(batchResp.getCode()) + "):" + batchResp.getMessage()); - } this.clearParameters(); // send @@ -1050,7 +976,7 @@ public void columnDataExecuteBatch() throws SQLException { } catch (IOException e) { throw new SQLException("data serialize error!", e); } - StmtResp bindResp = (StmtResp) transport.send(Action.SET_TAGS.getAction(), + Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.SET_TAGS.getAction(), reqId, stmtId, BindType.TAG.get(), tagBlock); if (Code.SUCCESS.getCode() != bindResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); @@ -1063,18 +989,11 @@ public void columnDataExecuteBatch() throws SQLException { } catch (IOException e) { throw new SQLException("data serialize error!", e); } - StmtResp bindResp = (StmtResp) transport.send(Action.BIND.getAction(), + Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.BIND.getAction(), reqId, stmtId, BindType.BIND.get(), rawBlock); if (Code.SUCCESS.getCode() != bindResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); } - // add batch - Request batch = RequestFactory.generateBatch(stmtId, reqId); - Response send = transport.send(batch); - StmtResp batchResp = (StmtResp) send; - if (Code.SUCCESS.getCode() != batchResp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(batchResp.getCode()) + "):" + batchResp.getMessage()); - } this.clearParameters(); // send diff --git a/src/main/java/com/taosdata/jdbc/ws/entity/Action.java b/src/main/java/com/taosdata/jdbc/ws/entity/Action.java index aadf82db..33616e9c 100644 --- a/src/main/java/com/taosdata/jdbc/ws/entity/Action.java +++ b/src/main/java/com/taosdata/jdbc/ws/entity/Action.java @@ -3,6 +3,7 @@ import com.taosdata.jdbc.ws.stmt.entity.ExecResp; import com.taosdata.jdbc.ws.stmt.entity.GetColFieldsResp; import com.taosdata.jdbc.ws.stmt.entity.StmtResp; +import com.taosdata.jdbc.ws.stmt2.entity.Stmt2Resp; import com.taosdata.jdbc.ws.tmq.entity.FetchRawBlockResp; import java.util.HashMap; @@ -35,6 +36,14 @@ public enum Action { CLOSE("close", StmtResp.class), + // stmt2 + STMT2_INIT("stmt2_init", Stmt2Resp.class), + STMT2_PREPARE("stmt2_prepare", Stmt2Resp.class), + STMT2_BIND("bind", Stmt2Resp.class), + STMT2_EXEC("exec", ExecResp.class), + // response means nothing + STMT2_CLOSE("close", StmtResp.class), + //schemaless INSERT("insert", CommonResp.class), ; diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/BindReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/BindReq.java new file mode 100644 index 00000000..64e8d2a1 --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/BindReq.java @@ -0,0 +1,29 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.taosdata.jdbc.utils.UInt64Serializer; +import com.taosdata.jdbc.ws.entity.Payload; + +public class BindReq extends Payload { + @JsonProperty("stmt_id") + @JsonSerialize(using = UInt64Serializer.class) + private long stmtId; + private Object[] columns; + + public long getStmtId() { + return stmtId; + } + + public void setStmtId(long stmtId) { + this.stmtId = stmtId; + } + + public Object[] getColumns() { + return columns; + } + + public void setColumns(Object[] columns) { + this.columns = columns; + } +} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/CloseReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/CloseReq.java new file mode 100644 index 00000000..68c5d160 --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/CloseReq.java @@ -0,0 +1,20 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.taosdata.jdbc.utils.UInt64Serializer; +import com.taosdata.jdbc.ws.entity.Payload; + +public class CloseReq extends Payload { + @JsonProperty("stmt_id") + @JsonSerialize(using = UInt64Serializer.class) + private long stmtId; + + public long getStmtId() { + return stmtId; + } + + public void setStmtId(long stmtId) { + this.stmtId = stmtId; + } +} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecReq.java new file mode 100644 index 00000000..badd7ccc --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecReq.java @@ -0,0 +1,20 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.taosdata.jdbc.utils.UInt64Serializer; +import com.taosdata.jdbc.ws.entity.Payload; + +public class ExecReq extends Payload { + @JsonProperty("stmt_id") + @JsonSerialize(using = UInt64Serializer.class) + private long stmtId; + + public long getStmtId() { + return stmtId; + } + + public void setStmtId(long stmtId) { + this.stmtId = stmtId; + } +} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecResp.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecResp.java new file mode 100644 index 00000000..9fb6fdbb --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecResp.java @@ -0,0 +1,28 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.taosdata.jdbc.utils.UInt64Deserializer; +import com.taosdata.jdbc.ws.entity.CommonResp; + +public class ExecResp extends CommonResp { + @JsonProperty("stmt_id") + @JsonDeserialize(using = UInt64Deserializer.class) + private long stmtId; + private int affected; + public long getStmtId() { + return stmtId; + } + + public void setStmtId(long stmtId) { + this.stmtId = stmtId; + } + + public int getAffected() { + return affected; + } + + public void setAffected(int affected) { + this.affected = affected; + } +} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java new file mode 100644 index 00000000..6d62b41c --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java @@ -0,0 +1,62 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Field { + private String name; + @JsonProperty("field_type") + private byte fieldType; + private byte precision; + private byte scale; + private int bytes; + + @JsonProperty("bind_type") + private byte bindType; + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public byte getFieldType() { + return fieldType; + } + + public void setFieldType(byte fieldType) { + this.fieldType = fieldType; + } + + public byte getPrecision() { + return precision; + } + + public void setPrecision(byte precision) { + this.precision = precision; + } + + public byte getScale() { + return scale; + } + + public void setScale(byte scale) { + this.scale = scale; + } + + public int getBytes() { + return bytes; + } + + public void setBytes(int bytes) { + this.bytes = bytes; + } + + public byte getBindType() { + return bindType; + } + + public void setBindType(byte bindType) { + this.bindType = bindType; + } +} \ No newline at end of file diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/InitReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/InitReq.java new file mode 100644 index 00000000..0f984c4e --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/InitReq.java @@ -0,0 +1,27 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.taosdata.jdbc.ws.entity.Payload; + +public class InitReq extends Payload { + @JsonProperty("single_stb_insert") + private boolean singleStbInsert; + @JsonProperty("single_table_bind_once") + private boolean singleTableBindOnce; + + public boolean isSingleStbInsert() { + return singleStbInsert; + } + + public void setSingleStbInsert(boolean singleStbInsert) { + this.singleStbInsert = singleStbInsert; + } + + public boolean isSingleTableBindOnce() { + return singleTableBindOnce; + } + + public void setSingleTableBindOnce(boolean singleTableBindOnce) { + this.singleTableBindOnce = singleTableBindOnce; + } +} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareReq.java new file mode 100644 index 00000000..5a91f155 --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareReq.java @@ -0,0 +1,39 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.taosdata.jdbc.utils.UInt64Serializer; +import com.taosdata.jdbc.ws.entity.Payload; + +public class PrepareReq extends Payload { + @JsonProperty("stmt_id") + @JsonSerialize(using = UInt64Serializer.class) + private long stmtId; + private String sql; + @JsonProperty("get_fields") + private boolean getFields = true; + public long getStmtId() { + return stmtId; + } + + public void setStmtId(long stmtId) { + this.stmtId = stmtId; + } + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + + public boolean isGetFields() { + return getFields; + } + + public void setGetFields(boolean getFields) { + this.getFields = getFields; + } +} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareResp.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareResp.java new file mode 100644 index 00000000..e5ccacb8 --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareResp.java @@ -0,0 +1,50 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.taosdata.jdbc.utils.UInt64Deserializer; +import com.taosdata.jdbc.ws.entity.CommonResp; + +import java.util.List; + +public class PrepareResp extends CommonResp { + @JsonProperty("stmt_id") + @JsonDeserialize(using = UInt64Deserializer.class) + private long stmtId; + private List fields; + @JsonProperty("fields_count") + private int fieldsCount; + @JsonProperty("is_insert") + private boolean isInsert; + public long getStmtId() { + return stmtId; + } + + public void setStmtId(long stmtId) { + this.stmtId = stmtId; + } + + public List getFields() { + return fields; + } + + public void setFields(List fields) { + this.fields = fields; + } + + public int getFieldsCount() { + return fieldsCount; + } + + public void setFieldsCount(int fieldsCount) { + this.fieldsCount = fieldsCount; + } + public boolean isInsert() { + return isInsert; + } + + public void setInsert(boolean insert) { + isInsert = insert; + } + +} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/RequestFactory.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/RequestFactory.java new file mode 100644 index 00000000..9f2e7550 --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/RequestFactory.java @@ -0,0 +1,52 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + + +import com.taosdata.jdbc.ws.entity.Action; +import com.taosdata.jdbc.ws.entity.Request; + +/** + * generate id for request + */ +public class RequestFactory { + + private RequestFactory() { + } + + public static Request generateInit(long reqId, boolean singleStbInsert, boolean singleTableBindOnce) { + InitReq initReq = new InitReq(); + initReq.setReqId(reqId); + initReq.setSingleStbInsert(singleStbInsert); + initReq.setSingleTableBindOnce(singleTableBindOnce); + return new Request(Action.STMT2_INIT.getAction(), initReq); + } + + public static Request generatePrepare(long stmtId, long reqId, String sql) { + PrepareReq prepareReq = new PrepareReq(); + prepareReq.setReqId(reqId); + prepareReq.setStmtId(stmtId); + prepareReq.setSql(sql); + return new Request(Action.STMT2_PREPARE.getAction(), prepareReq); + } + + public static Request generateBind(long stmtId, long reqId, Object[][] columns) { + BindReq req = new BindReq(); + req.setReqId(reqId); + req.setStmtId(stmtId); + req.setColumns(columns); + return new Request(Action.STMT2_BIND.getAction(), req); + } + + public static Request generateExec(long stmtId, long reqId) { + ExecReq req = new ExecReq(); + req.setReqId(reqId); + req.setStmtId(stmtId); + return new Request(Action.STMT2_EXEC.getAction(), req); + } + public static Request generateClose(long stmtId, long reqId) { + CloseReq req = new CloseReq(); + req.setReqId(reqId); + req.setStmtId(stmtId); + return new Request(Action.STMT2_CLOSE.getAction(), req); + } + +} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java new file mode 100644 index 00000000..ec540097 --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java @@ -0,0 +1,23 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.taosdata.jdbc.utils.UInt64Deserializer; +import com.taosdata.jdbc.ws.entity.CommonResp; + +// init | prepare | set_table_name | set_tags | bind | add_batch +public class Stmt2Resp extends CommonResp { + @JsonProperty("stmt_id") + @JsonDeserialize(using = UInt64Deserializer.class) + private long stmtId; + + + public long getStmtId() { + return stmtId; + } + + public void setStmtId(long stmtId) { + this.stmtId = stmtId; + } + +} From ff5518cc5d2172ae4f968112da283c2a7cf2ecf3 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Sun, 27 Oct 2024 11:47:53 +0800 Subject: [PATCH 02/15] mod stmt2 --- .../com/taosdata/jdbc/common/TableInfo.java | 4 +-- .../jdbc/ws/TSWSPreparedStatement.java | 10 ++----- .../jdbc/utils/InsertSqlPatternTest.java | 26 +------------------ .../taosdata/jdbc/ws/WSDriverBaseTest.java | 7 +++++ 4 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/taosdata/jdbc/common/TableInfo.java b/src/main/java/com/taosdata/jdbc/common/TableInfo.java index 3314492f..955007e3 100644 --- a/src/main/java/com/taosdata/jdbc/common/TableInfo.java +++ b/src/main/java/com/taosdata/jdbc/common/TableInfo.java @@ -6,8 +6,8 @@ public class TableInfo { private List dataList = new ArrayList<>(); - private final String tableName; - private final List; + private final String tableName = null; + private final List tagInfo = null; // taos data type private final int type; private final int index; diff --git a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java index f4307586..516fc1ce 100644 --- a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java +++ b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java @@ -52,7 +52,7 @@ public class TSWSPreparedStatement extends WSStatement implements PreparedStatem private final PriorityQueue queue = new PriorityQueue<>(); - private final + public TSWSPreparedStatement(Transport transport, ConnectionParam param, String database, AbstractConnection connection, String sql, Long instanceId) throws SQLException { super(transport, database, connection, instanceId); @@ -196,13 +196,7 @@ public int executeUpdate() throws SQLException { } // set sub-table name - public void setTableName(String name) throws SQLException { - Request request = RequestFactory.generateSetTableName(stmtId, reqId, name); - Stmt2Resp resp = (Stmt2Resp) transport.send(request); - if (Code.SUCCESS.getCode() != resp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); - } - } + public void setTagSqlTypeNull(int index, int type) throws SQLException { switch (type) { diff --git a/src/test/java/com/taosdata/jdbc/utils/InsertSqlPatternTest.java b/src/test/java/com/taosdata/jdbc/utils/InsertSqlPatternTest.java index 19d50307..859145a2 100644 --- a/src/test/java/com/taosdata/jdbc/utils/InsertSqlPatternTest.java +++ b/src/test/java/com/taosdata/jdbc/utils/InsertSqlPatternTest.java @@ -18,29 +18,5 @@ public class InsertSqlPatternTest { "insert into st.sub_t using db.sup_t (t1, t2) tags(?,?) (c1, c2) values(?, ?)", }; - @Test - public void test() { - for (String sql : sqls) { - Matcher matcher = TSWSPreparedStatement.INSERT_PATTERN.matcher(sql); - String db = null; - if (matcher.find()) { - if (matcher.group(1).equals("?") && matcher.group(3) != null) { - String usingGroup = matcher.group(3); - if (usingGroup.contains(".")) { - String[] split = usingGroup.split("\\."); - db = split[0]; - } - } else { - String usingGroup = matcher.group(1); - if (usingGroup.contains(".")) { - String[] split = usingGroup.split("\\."); - db = split[0]; - } - } - Assert.assertEquals("st", db); - } else { - throw new RuntimeException("not match sql: " + sql); - } - } - } + } diff --git a/src/test/java/com/taosdata/jdbc/ws/WSDriverBaseTest.java b/src/test/java/com/taosdata/jdbc/ws/WSDriverBaseTest.java index 53f49936..8a95f115 100644 --- a/src/test/java/com/taosdata/jdbc/ws/WSDriverBaseTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/WSDriverBaseTest.java @@ -32,6 +32,13 @@ public void queryBlock() throws SQLException { resultSet.next(); Assert.assertEquals(100, resultSet.getInt(2)); } + + + statement.execute("select 1 where 0"); + try (ResultSet resultSet = statement.executeQuery("select * from " + db_name + "." + tableName)) { + resultSet.next(); + Assert.assertEquals(100, resultSet.getInt(2)); + } } catch (SQLException e) { e.printStackTrace(); throw e; From f11d7badcfa802ae134d8d96cbe249525a9c44ae Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Fri, 1 Nov 2024 14:07:23 +0800 Subject: [PATCH 03/15] add stmt2 support --- .../com/taosdata/jdbc/AbstractStatement.java | 1 - .../taosdata/jdbc/TSDBPreparedStatement.java | 74 ++- .../com/taosdata/jdbc/common/ColumnInfo.java | 12 + .../taosdata/jdbc/common/SerializeBlock.java | 620 +++++++++++++----- .../com/taosdata/jdbc/common/TableInfo.java | 46 +- .../com/taosdata/jdbc/common/TagInfo.java | 38 -- .../jdbc/ws/TSWSPreparedStatement.java | 534 ++++++++------- .../java/com/taosdata/jdbc/ws/Transport.java | 42 +- .../jdbc/ws/stmt2/entity/Stmt2Resp.java | 32 +- 9 files changed, 905 insertions(+), 494 deletions(-) delete mode 100644 src/main/java/com/taosdata/jdbc/common/TagInfo.java diff --git a/src/main/java/com/taosdata/jdbc/AbstractStatement.java b/src/main/java/com/taosdata/jdbc/AbstractStatement.java index 7f443add..34a7d990 100644 --- a/src/main/java/com/taosdata/jdbc/AbstractStatement.java +++ b/src/main/java/com/taosdata/jdbc/AbstractStatement.java @@ -367,5 +367,4 @@ public boolean isCloseOnCompletion() throws SQLException { public Long getInstanceId(){ return this.instanceId; } - } diff --git a/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java b/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java index ef7fdeaf..639ee748 100644 --- a/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java +++ b/src/main/java/com/taosdata/jdbc/TSDBPreparedStatement.java @@ -24,28 +24,27 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.sql.*; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.PriorityQueue; +import java.sql.Date; +import java.util.*; /* * TDengine only supports a subset of the standard SQL, thus this implementation of the * standard JDBC API contains more or less some adjustments customized for certain * compatibility needs. */ -public class TSDBPreparedStatement extends TSDBStatement implements PreparedStatement { +public class TSDBPreparedStatement extends TSDBStatement implements TaosPrepareStatement { // for jdbc preparedStatement interface private String rawSql; private Object[] parameters = new Object[0]; // for parameter binding private long nativeStmtHandle; private String tableName; - private ArrayList tableTags; + private List tableTags; private int tagValueLength; private PriorityQueue queue = new PriorityQueue<>(); + TSDBPreparedStatement(TSDBConnection connection, String sql, Long instanceId) throws SQLException { super(connection, instanceId); this.rawSql = sql; @@ -370,7 +369,7 @@ public void setNClob(int parameterIndex, Reader reader) throws SQLException { // parameter binding private static class ColumnInfo implements Comparable { @SuppressWarnings("rawtypes") - private ArrayList data; + private List data; private int type; private int bytes; private boolean typeIsSet; @@ -416,6 +415,7 @@ public static TableTagInfo createNullTag(int type) { } } + @Override public void setTableName(String name) throws SQLException { if (this.nativeStmtHandle == 0) { @@ -437,65 +437,81 @@ private void ensureTagCapacity(int index) { } } + @Override public void setTagNull(int index, int type) { ensureTagCapacity(index); this.tableTags.set(index, TableTagInfo.createNullTag(type)); } + @Override public void setTagBoolean(int index, boolean value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_BOOL)); this.tagValueLength += Byte.BYTES; } + @Override public void setTagInt(int index, int value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_INT)); this.tagValueLength += Integer.BYTES; } + @Override public void setTagByte(int index, byte value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_TINYINT)); this.tagValueLength += Byte.BYTES; } + @Override public void setTagShort(int index, short value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_SMALLINT)); this.tagValueLength += Short.BYTES; } + @Override public void setTagLong(int index, long value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_BIGINT)); this.tagValueLength += Long.BYTES; } + @Override public void setTagTimestamp(int index, long value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP)); this.tagValueLength += Long.BYTES; } + @Override + public void setTagTimestamp(int index, Timestamp value) { + throw new RuntimeException("not supported"); + } + + @Override public void setTagFloat(int index, float value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_FLOAT)); this.tagValueLength += Float.BYTES; } + @Override public void setTagDouble(int index, double value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_DOUBLE)); this.tagValueLength += Double.BYTES; } + @Override public void setTagString(int index, String value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_BINARY)); this.tagValueLength += value.getBytes().length; } + @Override public void setTagNString(int index, String value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_NCHAR)); @@ -508,6 +524,7 @@ public void setTagNString(int index, String value) { } } + @Override public void setTagJson(int index, String value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_JSON)); @@ -520,75 +537,88 @@ public void setTagJson(int index, String value) { } } + @Override public void setTagVarbinary(int index, byte[] value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_VARBINARY)); this.tagValueLength += value.length; } + @Override public void setTagGeometry(int index, byte[] value) { ensureTagCapacity(index); this.tableTags.set(index, new TableTagInfo(value, TSDBConstants.TSDB_DATA_TYPE_GEOMETRY)); this.tagValueLength += value.length; } - public void setValueImpl(int columnIndex, ArrayList list, int type, int bytes) throws SQLException { + public void setValueImpl(int columnIndex, List list, int type, int bytes) throws SQLException { ColumnInfo p = new ColumnInfo(); p.setType(type); p.bytes = bytes; - p.data = (ArrayList) list.clone(); + p.data = list; p.index = columnIndex; queue.add(p); } - public void setInt(int columnIndex, ArrayList list) throws SQLException { + @Override + public void setInt(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_INT, Integer.BYTES); } - - public void setFloat(int columnIndex, ArrayList list) throws SQLException { + @Override + public void setFloat(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_FLOAT, Float.BYTES); } - public void setTimestamp(int columnIndex, ArrayList list) throws SQLException { + @Override + public void setTimestamp(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP, Long.BYTES); } - public void setLong(int columnIndex, ArrayList list) throws SQLException { + @Override + public void setLong(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_BIGINT, Long.BYTES); } - public void setDouble(int columnIndex, ArrayList list) throws SQLException { + @Override + public void setDouble(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_DOUBLE, Double.BYTES); } - public void setBoolean(int columnIndex, ArrayList list) throws SQLException { + @Override + public void setBoolean(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_BOOL, Byte.BYTES); } - public void setByte(int columnIndex, ArrayList list) throws SQLException { + public void setByte(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_TINYINT, Byte.BYTES); } - public void setShort(int columnIndex, ArrayList list) throws SQLException { + @Override + public void setShort(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_SMALLINT, Short.BYTES); } - public void setString(int columnIndex, ArrayList list, int size) throws SQLException { + @Override + public void setString(int columnIndex, List list, int size) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_BINARY, size); } - public void setVarbinary(int columnIndex, ArrayList list, int size) throws SQLException { + @Override + public void setVarbinary(int columnIndex, List list, int size) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_VARBINARY, size); } - public void setGeometry(int columnIndex, ArrayList list, int size) throws SQLException { + @Override + public void setGeometry(int columnIndex, List list, int size) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_GEOMETRY, size); } // note: expand the required space for each NChar character - public void setNString(int columnIndex, ArrayList list, int size) throws SQLException { + @Override + public void setNString(int columnIndex, List list, int size) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_NCHAR, size * Integer.BYTES); } + @Override public void columnDataAddBatch() throws SQLException { // pass the data block to native code if (rawSql == null) { diff --git a/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java b/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java index c30a7d02..43840261 100644 --- a/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java +++ b/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java @@ -9,6 +9,10 @@ public class ColumnInfo implements Comparable { private final int type; private final int index; + + + private int serializeSize; + public ColumnInfo(int columnIndex, Object data, int type) { this.index = columnIndex; this.dataList.add(data); @@ -37,6 +41,14 @@ public int getIndex() { return index; } + public int getSerializeSize() { + return serializeSize; + } + + public void setSerializeSize(int serializeSize) { + this.serializeSize = serializeSize; + } + @Override public int compareTo(ColumnInfo c) { return this.index > c.index ? 1 : -1; diff --git a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java index 0f428060..12d149e9 100644 --- a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java +++ b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java @@ -1,9 +1,11 @@ package com.taosdata.jdbc.common; import com.taosdata.jdbc.enums.TimestampPrecision; +import com.taosdata.jdbc.utils.StringUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.ByteBuffer; import java.sql.SQLException; import java.sql.Timestamp; import java.util.ArrayList; @@ -31,12 +33,12 @@ private static byte bmSetNull(byte c, int n) { return (byte) (c + (1 << (7 - bitPos(n)))); } - private static void handleBoolean(byte[] buf, int rowIndex, int offset, Object o){ + private static void handleBoolean(ByteArrayOutputStream buf, Object o){ boolean v = (Boolean) o; if (v) { - buf[offset + rowIndex] = 1; + buf.write(1); }else { - buf[offset + rowIndex] = 0; + buf.write(0); } } private static void SerializeInt(byte[] buf, int offset, int v){ @@ -45,6 +47,7 @@ private static void SerializeInt(byte[] buf, int offset, int v){ buf[offset + 2] = (byte) ((v >> 16) & 0xFF); buf[offset + 3] = (byte) ((v >> 24) & 0xFF); } + private static void SerializeLong(byte[] buf, int offset, long v){ buf[offset] = (byte) (v & 0xFF); buf[offset + 1] = (byte) ((v >> 8) & 0xFF); @@ -59,221 +62,492 @@ private static void SerializeShort(byte[] buf, int offset, short v){ buf[offset] = (byte) (v & 0xFF); buf[offset + 1] = (byte) ((v >> 8) & 0xFF); } - private static void handleNormalDataType(int dataType ,byte[] buf, int rowIndex, int startOffset, Object o, int precision) throws SQLException { + + public static void serializeByteArray(byte[] buf, int offset, byte[] data) { + System.arraycopy(data, 0, buf, offset, data.length); + } + + private static int serializeColumn(ColumnInfo columnInfo, byte[] buf, int offset, int precision) throws IOException, SQLException { + Integer dataLen = DataLengthCfg.getDataLength(columnInfo.getType()); + + // TotalLength + SerializeInt(buf, offset, columnInfo.getSerializeSize()); + offset += Integer.BYTES; + + // Type + SerializeInt(buf, offset, columnInfo.getType()); + offset += Integer.BYTES; + + // Num + SerializeInt(buf, offset, columnInfo.getDataList().size()); + offset += Integer.BYTES; + + // IsNull + for (int i = 0; i < columnInfo.getDataList().size(); i++) { + if (columnInfo.getDataList().get(i) == null) { + buf[offset++] = 1; + } else { + buf[offset++] = 0; + } + } + + // haveLength + if (dataLen != null){ + buf[offset++] = 0; + // buffer + SerializeNormalDataType(columnInfo.getType(), buf, offset, columnInfo.getDataList(), precision); + return offset; + } + + // data is array type + buf[offset++] = 1; + // length + for (Object o: columnInfo.getDataList()){ + if (o == null){ + SerializeInt(buf, offset, 0); + offset += Integer.BYTES; + } else { + switch (columnInfo.getType()) { + case TSDB_DATA_TYPE_BINARY: + case TSDB_DATA_TYPE_VARBINARY: + case TSDB_DATA_TYPE_GEOMETRY:{ + byte[] v = (byte[]) o; + SerializeInt(buf, offset, v.length); + offset += Integer.BYTES; + break; + } + case TSDB_DATA_TYPE_JSON: + case TSDB_DATA_TYPE_NCHAR: { + String v = (String) o; + SerializeInt(buf, offset, v.length()); + offset += Integer.BYTES; + break; + } + default: + throw new SQLException("unsupported data type : " + columnInfo.getType()); + } + } + } + + // Buffer + SerializeArrayDataType(columnInfo.getType(), buf, offset, columnInfo.getDataList()); + return offset; + } + + private static void SerializeNormalDataType(int dataType , byte[] buf, int offset, List objectList, int precision) throws IOException, SQLException { switch (dataType) { case TSDB_DATA_TYPE_BOOL: { - handleBoolean(buf, rowIndex, startOffset, o); + for (Object o: objectList){ + if (o == null) { + buf[offset++] = 0; + } else { + boolean v = (Boolean) o; + buf[offset++] = v ? (byte) 1 : (byte) 0; + } + } break; } case TSDB_DATA_TYPE_TINYINT: { - buf[rowIndex + startOffset] = (Byte) o; + for (Object o: objectList){ + if (o == null) { + buf[offset++] = 0; + } else { + byte v = (Byte) o; + buf[offset++] = v; + } + } break; } case TSDB_DATA_TYPE_SMALLINT: { - short v = (Short) o; - int offset = rowIndex * Short.BYTES + startOffset; - SerializeShort(buf, offset, v); + for (Object o: objectList){ + short v = 0; + if (o != null) { + v = (Short) o; + } + SerializeShort(buf, offset, v); + offset += Short.BYTES; + } break; } case TSDB_DATA_TYPE_INT: { - int v = (Integer) o; - int offset = rowIndex * Integer.BYTES + startOffset; - SerializeInt(buf, offset, v); + for (Object o: objectList){ + int v = 0; + if (o != null) { + v = (Integer) o; + } + SerializeInt(buf, offset, v); + offset += Integer.BYTES; + } break; } case TSDB_DATA_TYPE_BIGINT: { - long v = (Long) o; - int offset = rowIndex * Long.BYTES + startOffset; - SerializeLong(buf, offset, v); - break; + for (Object o: objectList){ + long v = 0; + if (o != null) { + v = (Long) o; + } + SerializeLong(buf, offset, v); + offset += Long.BYTES; + } + break; } case TSDB_DATA_TYPE_FLOAT: { - float v = (Float) o; - int offset = rowIndex * Float.BYTES + startOffset; - int f = Float.floatToIntBits(v); - SerializeInt(buf, offset, f); + for (Object o: objectList){ + float v = 0; + if (o != null) { + v = (Float) o; + } + int f = Float.floatToIntBits(v); + SerializeInt(buf, offset, f); + offset += Integer.BYTES; + } break; } case TSDB_DATA_TYPE_DOUBLE: { - double v = (Double) o; - int offset = rowIndex * Double.BYTES + startOffset; - long l = Double.doubleToLongBits(v); - SerializeLong(buf, offset, l); + for (Object o: objectList){ + double v = 0; + if (o != null) { + v = (Double) o; + } + long l = Double.doubleToLongBits(v); + SerializeLong(buf, offset, l); + offset += Long.BYTES; + } break; } case TSDB_DATA_TYPE_TIMESTAMP: { - Timestamp t = (Timestamp) o; - long v; - if (precision == TimestampPrecision.MS) { - v = t.getTime(); - } else if (precision == TimestampPrecision.US) { - v = t.getTime() * 1000L + t.getNanos() / 1000 % 1000; - } else { - v = t.getTime() * 1000_000L + t.getNanos() % 1000_000L; + for (Object o: objectList){ + if (o != null) { + Timestamp t = (Timestamp) o; + long v; + if (precision == TimestampPrecision.MS) { + v = t.getTime(); + } else if (precision == TimestampPrecision.US) { + v = t.getTime() * 1000L + t.getNanos() / 1000 % 1000; + } else { + v = t.getTime() * 1000_000L + t.getNanos() % 1000_000L; + } + SerializeLong(buf, offset, v); + offset += Long.BYTES; + } else { + SerializeLong(buf, offset, 0); + offset += Long.BYTES; + } } + break; + } + default: + throw new SQLException("unsupported data type : " + dataType); + } + } - int offset = rowIndex * Long.BYTES + startOffset; - SerializeLong(buf, offset, v); + private static void SerializeArrayDataType(int dataType , byte[] buf, int offset, List objectList) throws SQLException { + switch (dataType) { + case TSDB_DATA_TYPE_BINARY: + case TSDB_DATA_TYPE_VARBINARY: + case TSDB_DATA_TYPE_GEOMETRY:{ + for (Object o: objectList){ + if (o != null) { + byte[] v = (byte[]) o; + for (byte b : v) { + buf[offset++] = b; + } + } + } + break; + } + case TSDB_DATA_TYPE_JSON: + case TSDB_DATA_TYPE_NCHAR: { + for (Object o: objectList){ + if (o != null) { + String v = (String) o; + for (byte b : v.getBytes()) { + buf[offset++] = b; + } + } + } break; } default: throw new SQLException("unsupported data type : " + dataType); } } + public static int getTableNameTotalLength(List tableInfoList, int toBebindTableNameCount) throws SQLException{ + int totalLength = 0; + if (toBebindTableNameCount > 0){ + for ( TableInfo tableInfo: tableInfoList){ + if (StringUtils.isEmpty(tableInfo.getTableName())) { + throw new SQLException("table name is empty"); + } + totalLength += tableInfo.getTableName().length() + 1; + } + } + return totalLength; + } + public static int getTagTotalLengthByTableIndex(List tableInfoList, int index, int toBebindTagCount) throws SQLException{ + int totalLength = 0; + if (toBebindTagCount > 0){ + if (tableInfoList.get(index).getTagInfo().size() != toBebindTagCount){ + throw new SQLException("table tag size is not match"); + } + for (ColumnInfo tag : tableInfoList.get(index).getTagInfo()){ + if (tag.getDataList().get(index) == null){ + throw new SQLException("tag value is null, index: " + index); + } + int columnSize = getColumnSize(tag); + tag.setSerializeSize(columnSize); + totalLength += columnSize; + } + } + return totalLength; + } - public static byte[] getRawBlock(List list, int precision) throws IOException, SQLException { - int columns = list.size(); - int rows = list.get(0).getDataList().size(); - - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - // version int32 - buffer.write(intToBytes(1)); - // length int32 - buffer.write(intToBytes(0)); - // rows int32 - buffer.write(intToBytes(rows)); - // columns int32 - buffer.write(intToBytes(columns)); - // flagSegment int32 - buffer.write(intToBytes(0)); - // groupID uint64 - buffer.write(longToBytes(0)); - - byte[] colInfoData = new byte[5 * columns]; - byte[] lengthData = new byte[4 * columns]; - - int bitMapLen = bitMapLen(rows); - ByteArrayOutputStream data = new ByteArrayOutputStream(); - for (int colIndex = 0; colIndex < list.size(); colIndex++) { - ColumnInfo column = list.get(colIndex); - - Integer dataLen = DataLengthCfg.getDataLength(column.getType()); - - // 不支持的数据类型 - if (column.getType() == TSDB_DATA_TYPE_UTINYINT - || column.getType() == TSDB_DATA_TYPE_USMALLINT - || column.getType() == TSDB_DATA_TYPE_UINT - || column.getType() == TSDB_DATA_TYPE_UBIGINT - ) { - break; + public static int getColTotalLengthByTableIndex(List tableInfoList, int index, int toBebindColCount) throws SQLException{ + int totalLength = 0; + if (toBebindColCount > 0){ + if (tableInfoList.get(index).getDataList().size() != toBebindColCount){ + throw new SQLException("table column size is not match"); } - //非数组类型 - if (dataLen != null){ - colInfoData[colIndex * 5] = (byte) column.getType(); - int typeLen = dataLen; + for (ColumnInfo columnInfo : tableInfoList.get(index).getDataList()){ + if (columnInfo.getDataList().get(index) == null){ + throw new SQLException("col value is null, index: " + index); + } + int columnSize = getColumnSize(columnInfo); + columnInfo.setSerializeSize(columnSize); + totalLength += columnSize; + } + } + return totalLength; + } - byte[] typeBytes = intToBytes(typeLen); - System.arraycopy(typeBytes, 0, colInfoData, colIndex * 5 + 1, 4); - byte[] array = intToBytes(typeLen * rows); - System.arraycopy(array, 0, lengthData, colIndex * 4, 4); + public static int getColumnSize(ColumnInfo column) throws SQLException { + Integer dataLen = DataLengthCfg.getDataLength(column.getType()); - byte[] tmp = new byte[bitMapLen + rows * dataLen]; - List rowData = column.getDataList(); + if (dataLen != null) { + // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + size * dataLen + return 17 + (dataLen + 1) * column.getDataList().size(); + } - for (int rowIndex = 0; rowIndex < rows; rowIndex++) { - if (rowData.get(rowIndex) == null) { - int charOffset = charOffset(rowIndex); - tmp[charOffset] = bmSetNull(tmp[charOffset], rowIndex); - } else { - handleNormalDataType(column.getType(), tmp, rowIndex, bitMapLen, rowData.get(rowIndex), precision); + switch (column.getType()) { + case TSDB_DATA_TYPE_BINARY: + case TSDB_DATA_TYPE_VARBINARY: + case TSDB_DATA_TYPE_GEOMETRY:{ + int totalLength = 0; + for (Object o : column.getDataList()) { + if (o != null) { + byte[] v = (byte[]) o; + totalLength += v.length; } } - data.write(tmp); - }else{ - // 数组类型 - switch (column.getType()) { - case TSDB_DATA_TYPE_BINARY: - case TSDB_DATA_TYPE_JSON: - case TSDB_DATA_TYPE_VARBINARY: - case TSDB_DATA_TYPE_GEOMETRY: - { - colInfoData[colIndex * 5] = (byte) column.getType(); - // 4 bytes for 0 - - int length = 0; - List rowData = column.getDataList(); - byte[] index = new byte[rows * Integer.BYTES]; - List tmp = new ArrayList<>(); - for (int rowIndex = 0; rowIndex < rows; rowIndex++) { - int offset = rowIndex * Integer.BYTES; - if (rowData.get(rowIndex) == null) { - for (int i = 0; i < Integer.BYTES; i++) { - index[offset + i] = (byte) 0xFF; - } - } else { - byte[] v = (byte[]) rowData.get(rowIndex); - for (int i = 0; i < Integer.BYTES; i++) { - index[offset + i] = (byte) (length >> (8 * i) & 0xFF); - } - short len = (short) v.length; - tmp.add((byte) (len & 0xFF)); - tmp.add((byte) ((len >> 8) & 0xFF)); - for (byte b : v) { - tmp.add(b); - } - length += v.length + Short.BYTES; - } - } - byte[] array = intToBytes(length); - System.arraycopy(array, 0, lengthData, colIndex * 4, 4); - data.write(index); - byte[] bytes = new byte[tmp.size()]; - for (int i = 0; i < tmp.size(); i++) { - bytes[i] = tmp.get(i); - } - data.write(bytes); - break; + // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + 4 + v.length + totalLength + return 17 + (5 * column.getDataList().size()) + totalLength; + } + case TSDB_DATA_TYPE_JSON: + case TSDB_DATA_TYPE_NCHAR: { + int totalLength = 0; + for (Object o : column.getDataList()) { + if (o != null) { + String v = (String) o; + totalLength += v.length(); } - case TSDB_DATA_TYPE_NCHAR: { - colInfoData[colIndex * 5] = (byte) column.getType();; - // 4 bytes for 0 - - int length = 0; - byte[] index = new byte[rows * Integer.BYTES]; - ByteArrayOutputStream tmp = new ByteArrayOutputStream(); - List rowData = column.getDataList(); - for (int rowIndex = 0; rowIndex < rows; rowIndex++) { - int offset = rowIndex * Integer.BYTES; - if (rowData.get(rowIndex) == null) { - for (int i = 0; i < Integer.BYTES; i++) { - index[offset + i] = (byte) 0xFF; - } - } else { - String v = (String) rowData.get(rowIndex); - for (int i = 0; i < Integer.BYTES; i++) { - index[offset + i] = (byte) ((length >> (8 * i)) & 0xFF); - } - short len = (short) (v.length() * 4); - tmp.write((byte) (len & 0xFF)); - tmp.write((byte) ((len >> 8) & 0xFF)); - int[] t = v.codePoints().toArray(); - for (int i : t) { - tmp.write(intToBytes(i)); - } - length += t.length * 4 + Short.BYTES; - } - } - byte[] array = intToBytes(length); - System.arraycopy(array, 0, lengthData, colIndex * 4, 4); - data.write(index); - data.write(tmp.toByteArray()); - break; + } + // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + 4 + v.length + totalLength + return 17 + (5 * column.getDataList().size()) + totalLength; + } + default: + throw new SQLException("unsupported data type : " + column.getType()); + } + } + + + + + public static byte[] getStmt2BindBlock(long reqId, + long stmtId, + List tableInfoList, + int toBebindTableNameCount, + int toBebindTagCount, + int toBebindColCount, + int precision) throws IOException, SQLException { + + // cloc totol size + int totalTableNameSize = 0; + List tableNameSizeList = new ArrayList<>(); + for (int i = 0; i < tableInfoList.size(); i++) { + int tableNameSize = getTableNameTotalLength(tableInfoList, toBebindTableNameCount); + totalTableNameSize += tableNameSize; + tableNameSizeList.add((short)tableNameSize); + } + + int totalagSize = 0; + List tagSizeList = new ArrayList<>(); + + for (int i = 0; i < tableInfoList.size(); i++) { + int tagSize = getTagTotalLengthByTableIndex(tableInfoList, i, toBebindTagCount); + totalagSize += tagSize; + tagSizeList.add(tagSize); + } + + int totalColSize = 0; + List colSizeList = new ArrayList<>(); + for (int i = 0; i < tableInfoList.size(); i++) { + int colSize = getColTotalLengthByTableIndex(tableInfoList, i, toBebindColCount); + totalColSize += colSize; + colSizeList.add(colSize); + } + + int totalSize = totalTableNameSize + totalagSize + totalColSize; + totalSize += tagSizeList.size() * (toBebindTableNameCount * Short.BYTES + toBebindTagCount * Integer.BYTES + toBebindColCount * Integer.BYTES); + + byte[] buf = new byte[30 + totalSize]; + int offset = 0; + + //************ header ***************** + // ReqId + SerializeLong(buf, offset, reqId); + offset += Long.BYTES; + // stmtId + SerializeLong(buf, offset, stmtId); + offset += Long.BYTES; + // actionId + SerializeLong(buf, offset, 9L); + offset += Long.BYTES; + + // version + SerializeShort(buf, offset, (short) 1); + offset += Short.BYTES; + + // col_idx + SerializeInt(buf, offset, -1); + offset += Integer.BYTES; + + //************ data ***************** + // TotalLength + SerializeInt(buf, offset, totalSize); + offset += Integer.BYTES; + + // tableCount + SerializeInt(buf, offset, tableInfoList.size()); + offset += Integer.BYTES; + + // TagCount + SerializeInt(buf, offset, toBebindTagCount); + offset += Integer.BYTES; + + // ColCount + SerializeInt(buf, offset, toBebindColCount); + offset += Integer.BYTES; + + // tableNameOffset + int totalTableNameOffset = 0; + if (toBebindTableNameCount > 0){ + SerializeInt(buf, offset, 0x1C); + offset += Integer.BYTES; + } else { + SerializeInt(buf, offset, 0); + offset += Integer.BYTES; + } + + // tagOffset + if (toBebindTagCount > 0){ + if (toBebindTableNameCount > 0){ + SerializeInt(buf, offset, 28 + totalTableNameSize + Short.BYTES * tableInfoList.size()); + offset += Integer.BYTES; + } else { + SerializeInt(buf, offset, 28); + offset += Integer.BYTES; + } + } else { + SerializeInt(buf, offset, 0); + offset += Integer.BYTES; + } + + // colOffset + if (toBebindColCount > 0){ + int skipSize = 0; + if (toBebindTableNameCount > 0){ + skipSize += totalTableNameSize + Short.BYTES * tableInfoList.size(); + } + + if (toBebindTagCount > 0){ + skipSize += totalagSize + Integer.BYTES * tableInfoList.size(); + } + SerializeInt(buf, offset, 28 + skipSize); + offset += Integer.BYTES; + } else { + SerializeInt(buf, offset, 0); + offset += Integer.BYTES; + } + + // TableNameLength + if (toBebindTableNameCount > 0){ + for (Short tabeNameLen: tableNameSizeList){ + if (tabeNameLen == 0) { + throw new SQLException("table name is empty"); + } + + SerializeShort(buf, offset, (short)(tabeNameLen + 1)); + offset += Short.BYTES; + } + + for (TableInfo tableInfo: tableInfoList){ + if (StringUtils.isEmpty(tableInfo.getTableName())) { + throw new SQLException("table name is empty"); + } + + serializeByteArray(buf, offset, tableInfo.getTableName().getBytes()); + offset += tableInfo.getTableName().length(); + buf[offset++] = 0; + } + } + + // TagsDataLength + if (toBebindTagCount > 0){ + for (Integer tagsize: tagSizeList) { + SerializeInt(buf, offset, tagsize); + offset += Integer.BYTES; + } + + for (int i = 0; i < tableInfoList.size(); i++) { + for (ColumnInfo tag : tableInfoList.get(i).getTagInfo()){ + if (tag.getDataList().get(i) == null){ + throw new SQLException("tag value is null, index: " + i); } - default: - throw new SQLException("unsupported data type : " + column.getType()); + serializeColumn(tag, buf, offset, precision); + offset += tag.getSerializeSize(); } } } - buffer.write(colInfoData); - buffer.write(lengthData); - buffer.write(data.toByteArray()); - byte[] block = buffer.toByteArray(); - for (int i = 0; i < Integer.BYTES; i++) { - block[4 + i] = (byte) (block.length >> (8 * i)); + + // TagsDataLength + if (toBebindColCount > 0){ + for (Integer colSize: colSizeList) { + SerializeInt(buf, offset, colSize); + offset += Integer.BYTES; + } + + for (int i = 0; i < tableInfoList.size(); i++) { + for (ColumnInfo col : tableInfoList.get(i).getDataList()){ + if (col.getDataList().get(i) == null){ + throw new SQLException("tag value is null, index: " + i); + } + serializeColumn(col, buf, offset, precision); + offset += col.getSerializeSize(); + } + } } - return block; + + return buf; + } + + // little endian + public static byte[] shortToBytes(int v) { + byte[] result = new byte[2]; + result[0] = (byte) (v & 0xFF); + result[1] = (byte) ((v >> 8) & 0xFF); + return result; } // little endian diff --git a/src/main/java/com/taosdata/jdbc/common/TableInfo.java b/src/main/java/com/taosdata/jdbc/common/TableInfo.java index 955007e3..24596440 100644 --- a/src/main/java/com/taosdata/jdbc/common/TableInfo.java +++ b/src/main/java/com/taosdata/jdbc/common/TableInfo.java @@ -4,40 +4,42 @@ import java.util.List; public class TableInfo { - private List dataList = new ArrayList<>(); + private List dataList; + private String tableName; + private List tagInfo; - private final String tableName = null; - private final List tagInfo = null; - // taos data type - private final int type; - private final int index; + public TableInfo(List dataList, String tableName, List tagInfo) { + this.dataList = dataList; + this.tableName = tableName; + this.tagInfo = tagInfo; + } - public TableInfo(int columnIndex, Object data, int type) { - this.index = columnIndex; - this.dataList.add(data); - this.type = type; + public static TableInfo getEmptyTableInfo() { + return new TableInfo(new ArrayList<>(), "", new ArrayList<>()); + } + public List getDataList() { + return dataList; } - public TableInfo(int columnIndex, List dataList, int type, Integer flag) { - this.index = columnIndex; - this.dataList = dataList; - this.type = type; + public String getTableName() { + return tableName; } - public void add(Object data) { - this.dataList.add(data); + public List getTagInfo() { + return tagInfo; } - public List getDataList() { - return dataList; + public void setDataList(List dataList) { + this.dataList = dataList; } - public int getType() { - return type; + public void setTableName(String tableName) { + this.tableName = tableName; } - public int getIndex() { - return index; + public void setTagInfo(List tagInfo) { + this.tagInfo = tagInfo; } + } diff --git a/src/main/java/com/taosdata/jdbc/common/TagInfo.java b/src/main/java/com/taosdata/jdbc/common/TagInfo.java deleted file mode 100644 index 6c4fa0f3..00000000 --- a/src/main/java/com/taosdata/jdbc/common/TagInfo.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.taosdata.jdbc.common; - -import java.util.ArrayList; -import java.util.List; - -public class TagInfo implements Comparable { - private Object data; - // taos data type - private final int type; - private final int index; - - public TagInfo(int index, Object data, int type) { - this.index = index; - this.data = data; - this.type = type; - } - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } - - public int getType() { - return type; - } - - public int getIndex() { - return index; - } - - @Override - public int compareTo(TagInfo c) { - return this.index > c.index ? 1 : -1; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java index 516fc1ce..526e96d6 100644 --- a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java +++ b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java @@ -3,7 +3,8 @@ import com.taosdata.jdbc.*; import com.taosdata.jdbc.common.ColumnInfo; import com.taosdata.jdbc.common.SerializeBlock; -import com.taosdata.jdbc.enums.BindType; +import com.taosdata.jdbc.common.TableInfo; +import com.taosdata.jdbc.enums.FeildBindType; import com.taosdata.jdbc.enums.TimestampPrecision; import com.taosdata.jdbc.rs.ConnectionParam; import com.taosdata.jdbc.utils.ReqId; @@ -11,7 +12,6 @@ import com.taosdata.jdbc.ws.entity.Action; import com.taosdata.jdbc.ws.entity.Code; import com.taosdata.jdbc.ws.entity.Request; -import com.taosdata.jdbc.ws.entity.Response; import com.taosdata.jdbc.ws.stmt2.entity.*; import java.io.IOException; @@ -24,15 +24,13 @@ import java.sql.*; import java.time.LocalDateTime; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Pattern; import java.util.stream.Collectors; import static com.taosdata.jdbc.TSDBConstants.*; -import static com.taosdata.jdbc.utils.SqlSyntaxValidator.getDatabaseName; -import static com.taosdata.jdbc.utils.SqlSyntaxValidator.isUseSql; -public class TSWSPreparedStatement extends WSStatement implements PreparedStatement { +public class TSWSPreparedStatement extends WSStatement implements TaosPrepareStatement { + private static final List nullTag = Collections.singletonList(null); + private final ConnectionParam param; private long reqId; private long stmtId; @@ -40,18 +38,20 @@ public class TSWSPreparedStatement extends WSStatement implements PreparedStatem private int queryTimeout = 0; private int precision = TimestampPrecision.MS; + private int toBeBindTableNameCount = 0; private int toBeBindColCount = 0; + private int toBeBindTagCount = 0; private List fields; private boolean isInsert = false; private final Map column = new HashMap<>(); - private final Map tag = new HashMap<>(); - private final List data = new ArrayList<>(); - + private final PriorityQueue tag = new PriorityQueue<>(); private final PriorityQueue queue = new PriorityQueue<>(); + private List tableInfoList = new ArrayList<>(); + private TableInfo tableInfo; public TSWSPreparedStatement(Transport transport, ConnectionParam param, String database, AbstractConnection connection, String sql, Long instanceId) throws SQLException { @@ -69,23 +69,41 @@ public TSWSPreparedStatement(Transport transport, ConnectionParam param, String } stmtId = resp.getStmtId(); Request prepare = RequestFactory.generatePrepare(stmtId, reqId, sql); - PrepareResp prepareResp = (PrepareResp) transport.send(prepare); + Stmt2Resp prepareResp = (Stmt2Resp) transport.send(prepare); if (Code.SUCCESS.getCode() != prepareResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(prepareResp.getCode()) + "):" + prepareResp.getMessage()); } - if (prepareResp.getFieldsCount() != prepareResp.getFields().size()){ - throw new SQLException("prepare error: fields count not match"); - } +// if (prepareResp.getFieldsCount() != prepareResp.getFields().size()){ +// throw new SQLException("prepare error: fields count not match"); +// } isInsert = prepareResp.isInsert(); - if (prepareResp.getFieldsCount() > 0){ - toBeBindColCount = prepareResp.getFieldsCount(); + if (isInsert){ fields = prepareResp.getFields(); - } else{ + for (Field field : fields){ + if (field.getBindType() == FeildBindType.TAOS_FIELD_TBNAME.getValue()){ + toBeBindTableNameCount++; + } + if (field.getBindType() == FeildBindType.TAOS_FIELD_TAG.getValue()){ + toBeBindTagCount ++; + } + if (field.getBindType() == FeildBindType.TAOS_FIELD_COL.getValue()){ + toBeBindColCount ++; + } + } + } else if (!isInsert && prepareResp.getFieldsCount() > 0){ + for (Field field : fields){ + if (field.getBindType() == FeildBindType.TAOS_FIELD_QUERY.getValue()){ + toBeBindColCount ++; + } + } + } else { return; } + this.tableInfo = TableInfo.getEmptyTableInfo(); + // now we know the number of fields, we can prepare the cache data if (prepareResp.isInsert()){ // for (int i = 0; i < toBeBindColCount; i++){ @@ -123,76 +141,81 @@ public boolean execute(String sql, Long reqId) throws SQLException { @Override public ResultSet executeQuery() throws SQLException { - List list = new ArrayList<>(); - if (!tag.isEmpty()) { - tag.keySet().stream().sorted().forEach(i -> { - Column col = this.tag.get(i); - list.add(col.data); - }); - } - if (!column.isEmpty()) { - column.keySet().stream().sorted().forEach(i -> { - Column col = this.column.get(i); - list.add(col.data); - }); - } - Object[] parameters = list.toArray(new Object[0]); - this.clearParameters(); - - final String sql = Utils.getNativeSql(this.rawSql, parameters); - return executeQuery(sql); +// List list = new ArrayList<>(); +// if (!tag.isEmpty()) { +// tag.keySet().stream().sorted().forEach(i -> { +// Column col = this.tag.get(i); +// list.add(col.data); +// }); +// } +// if (!column.isEmpty()) { +// column.keySet().stream().sorted().forEach(i -> { +// Column col = this.column.get(i); +// list.add(col.data); +// }); +// } +// Object[] parameters = list.toArray(new Object[0]); +// this.clearParameters(); +// +// final String sql = Utils.getNativeSql(this.rawSql, parameters); +// return executeQuery(sql); + + + return null; } @Override public int executeUpdate() throws SQLException { - if (column.isEmpty()) - throw new SQLException("no parameter to execute"); - if (!data.isEmpty()) - throw TSDBError.undeterminedExecutionError(); - - //set tag - if (!tag.isEmpty()) { - List collect = tag.keySet().stream().sorted().map(i -> { - Column col = this.tag.get(i); - return new ColumnInfo(i, col.data, col.type); - }).collect(Collectors.toList()); - byte[] tagBlock; - try { - tagBlock = SerializeBlock.getRawBlock(collect, precision); - } catch (IOException e) { - throw new SQLException("data serialize error!", e); - } - Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.SET_TAGS.getAction(), - reqId, stmtId, BindType.TAG.get(), tagBlock); - if (Code.SUCCESS.getCode() != bindResp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); - } - } - // bind - List collect = column.keySet().stream().sorted().map(i -> { - Column col = this.column.get(i); - return new ColumnInfo(i, col.data, col.type); - }).collect(Collectors.toList()); - byte[] rawBlock; - try { - rawBlock = SerializeBlock.getRawBlock(collect, precision); - } catch (IOException e) { - throw new SQLException("data serialize error!", e); - } - Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.BIND.getAction(), - reqId, stmtId, BindType.BIND.get(), rawBlock); - if (Code.SUCCESS.getCode() != bindResp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); - } - this.clearParameters(); - // send - Request request = RequestFactory.generateExec(stmtId, reqId); - ExecResp resp = (ExecResp) transport.send(request); - if (Code.SUCCESS.getCode() != resp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage(), "P0001", resp.getCode()); - } - - return resp.getAffected(); +// if (column.isEmpty()) +// throw new SQLException("no parameter to execute"); +// if (!data.isEmpty()) +// throw TSDBError.undeterminedExecutionError(); +// +// //set tag +// if (!tag.isEmpty()) { +// List collect = tag.keySet().stream().sorted().map(i -> { +// Column col = this.tag.get(i); +// return new ColumnInfo(i, col.data, col.type); +// }).collect(Collectors.toList()); +// byte[] tagBlock; +// try { +// tagBlock = SerializeBlock.getRawBlock(collect, precision); +// } catch (IOException e) { +// throw new SQLException("data serialize error!", e); +// } +// Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.SET_TAGS.getAction(), +// reqId, stmtId, BindType.TAG.get(), tagBlock); +// if (Code.SUCCESS.getCode() != bindResp.getCode()) { +// throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); +// } +// } +// // bind +// List collect = column.keySet().stream().sorted().map(i -> { +// Column col = this.column.get(i); +// return new ColumnInfo(i, col.data, col.type); +// }).collect(Collectors.toList()); +// byte[] rawBlock; +// try { +// rawBlock = SerializeBlock.getRawBlock(collect, precision); +// } catch (IOException e) { +// throw new SQLException("data serialize error!", e); +// } +// Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.BIND.getAction(), +// reqId, stmtId, BindType.BIND.get(), rawBlock); +// if (Code.SUCCESS.getCode() != bindResp.getCode()) { +// throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); +// } +// this.clearParameters(); +// // send +// Request request = RequestFactory.generateExec(stmtId, reqId); +// ExecResp resp = (ExecResp) transport.send(request); +// if (Code.SUCCESS.getCode() != resp.getCode()) { +// throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage(), "P0001", resp.getCode()); +// } +// +// return resp.getAffected(); + + return 0; } // set sub-table name @@ -201,150 +224,165 @@ public int executeUpdate() throws SQLException { public void setTagSqlTypeNull(int index, int type) throws SQLException { switch (type) { case Types.BOOLEAN: - tag.put(index, new Column(null, TSDB_DATA_TYPE_BOOL, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_BOOL)); break; case Types.TINYINT: - tag.put(index, new Column(null, TSDB_DATA_TYPE_TINYINT, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_TINYINT)); break; case Types.SMALLINT: - tag.put(index, new Column(null, TSDB_DATA_TYPE_SMALLINT, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_SMALLINT)); break; case Types.INTEGER: - tag.put(index, new Column(null, TSDB_DATA_TYPE_INT, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_INT)); break; case Types.BIGINT: - tag.put(index, new Column(null, TSDB_DATA_TYPE_BIGINT, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_BIGINT)); break; case Types.FLOAT: - tag.put(index, new Column(null, TSDB_DATA_TYPE_FLOAT, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_FLOAT)); break; case Types.DOUBLE: - tag.put(index, new Column(null, TSDB_DATA_TYPE_DOUBLE, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_DOUBLE)); break; case Types.TIMESTAMP: - tag.put(index, new Column(null, TSDB_DATA_TYPE_TIMESTAMP, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_TIMESTAMP)); break; case Types.BINARY: case Types.VARCHAR: - tag.put(index, new Column(null, TSDB_DATA_TYPE_BINARY, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_BINARY)); break; case Types.VARBINARY: - tag.put(index, new Column(null, TSDB_DATA_TYPE_VARBINARY, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_VARBINARY)); break; case Types.NCHAR: - tag.put(index, new Column(null, TSDB_DATA_TYPE_NCHAR, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_NCHAR)); break; // json case Types.OTHER: - tag.put(index, new Column(null, TSDB_DATA_TYPE_JSON, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_JSON)); break; default: throw new SQLException("unsupported type: " + type); } } + @Override public void setTagNull(int index, int type) throws SQLException { switch (type) { case TSDB_DATA_TYPE_BOOL: - tag.put(index, new Column(null, TSDB_DATA_TYPE_BOOL, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_BOOL)); break; case TSDB_DATA_TYPE_TINYINT: - tag.put(index, new Column(null, TSDB_DATA_TYPE_TINYINT, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_TINYINT)); break; case TSDB_DATA_TYPE_SMALLINT: - tag.put(index, new Column(null, TSDB_DATA_TYPE_SMALLINT, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_SMALLINT)); break; case TSDB_DATA_TYPE_INT: - tag.put(index, new Column(null, TSDB_DATA_TYPE_INT, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_INT)); break; case TSDB_DATA_TYPE_BIGINT: - tag.put(index, new Column(null, TSDB_DATA_TYPE_BIGINT, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_BIGINT)); break; case TSDB_DATA_TYPE_FLOAT: - tag.put(index, new Column(null, TSDB_DATA_TYPE_FLOAT, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_FLOAT)); break; case TSDB_DATA_TYPE_DOUBLE: - tag.put(index, new Column(null, TSDB_DATA_TYPE_DOUBLE, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_DOUBLE)); break; case TSDB_DATA_TYPE_TIMESTAMP: - tag.put(index, new Column(null, TSDB_DATA_TYPE_TIMESTAMP, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_TIMESTAMP)); break; case TSDB_DATA_TYPE_BINARY: - tag.put(index, new Column(null, TSDB_DATA_TYPE_BINARY, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_BINARY)); break; case TSDB_DATA_TYPE_VARBINARY: - tag.put(index, new Column(null, TSDB_DATA_TYPE_VARBINARY, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_VARBINARY)); break; case TSDB_DATA_TYPE_GEOMETRY: - tag.put(index, new Column(null, TSDB_DATA_TYPE_GEOMETRY, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_GEOMETRY)); break; case TSDB_DATA_TYPE_NCHAR: - tag.put(index, new Column(null, TSDB_DATA_TYPE_NCHAR, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_NCHAR)); break; // json case TSDB_DATA_TYPE_JSON: - tag.put(index, new Column(null, TSDB_DATA_TYPE_JSON, index)); + tag.add(new ColumnInfo(index, nullTag, TSDB_DATA_TYPE_JSON)); break; default: throw new SQLException("unsupported type: " + type); } } + @Override public void setTagBoolean(int index, boolean value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_BOOL, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_BOOL)); } + @Override public void setTagByte(int index, byte value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_TINYINT, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_TINYINT)); } + @Override public void setTagShort(int index, short value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_SMALLINT, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_SMALLINT)); } + @Override public void setTagInt(int index, int value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_INT, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_INT)); } + @Override public void setTagLong(int index, long value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_BIGINT, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_BIGINT)); } + @Override public void setTagFloat(int index, float value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_FLOAT, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_FLOAT)); } + @Override public void setTagDouble(int index, double value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_DOUBLE, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_DOUBLE)); } + @Override public void setTagTimestamp(int index, long value) { - tag.put(index, new Column(new Timestamp(value), TSDB_DATA_TYPE_TIMESTAMP, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(new Timestamp(value)), TSDB_DATA_TYPE_TIMESTAMP)); } + @Override public void setTagTimestamp(int index, Timestamp value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_TIMESTAMP, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_TIMESTAMP)); } + @Override public void setTagString(int index, String value) { byte[] bytes = value.getBytes(StandardCharsets.UTF_8); - tag.put(index, new Column(bytes, TSDB_DATA_TYPE_BINARY, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(bytes), TSDB_DATA_TYPE_BINARY)); } + @Override public void setTagVarbinary(int index, byte[] value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_VARBINARY, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_VARBINARY)); } + @Override public void setTagGeometry(int index, byte[] value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_GEOMETRY, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_GEOMETRY)); } + @Override public void setTagNString(int index, String value) { - tag.put(index, new Column(value, TSDB_DATA_TYPE_NCHAR, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(value), TSDB_DATA_TYPE_NCHAR)); } + @Override public void setTagJson(int index, String value) { byte[] bytes = value.getBytes(StandardCharsets.UTF_8); - tag.put(index, new Column(bytes, TSDB_DATA_TYPE_JSON, index)); + tag.add(new ColumnInfo(index, Collections.singletonList(bytes), TSDB_DATA_TYPE_JSON)); } @Override @@ -506,7 +544,11 @@ public void setBinaryStream(int parameterIndex, InputStream x, int length) throw public void clearParameters() throws SQLException { column.clear(); tag.clear(); - data.clear(); + + tableInfo.setTableName(""); + tableInfo.getTagInfo().clear(); + tableInfo.getDataList().clear(); + tableInfoList.clear(); } @Override @@ -594,12 +636,12 @@ public boolean execute() throws SQLException { throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); List list = new ArrayList<>(); - if (!tag.isEmpty()) { - tag.keySet().stream().sorted().forEach(i -> { - Column col = this.tag.get(i); - list.add(col.data); - }); - } +// if (!tag.isEmpty()) { +// tag.keySet().stream().sorted().forEach(i -> { +// Column col = this.tag.get(i); +// list.add(col.data); +// }); +// } if (!column.isEmpty()) { column.keySet().stream().sorted().forEach(i -> { Column col = this.column.get(i); @@ -614,77 +656,78 @@ public boolean execute() throws SQLException { @Override public void addBatch() throws SQLException { - List collect = column.keySet().stream().sorted().map(column::get).collect(Collectors.toList()); - if (data.isEmpty()) { - for (Column col : collect) { - data.add(new ColumnInfo(col.index, col.data, col.type)); - } - } else { - if (collect.size() != data.size()) { - throw new SQLException("batch add column size not match, expected: " + data.size() + ", actual: " + collect.size()); - } - - for (int i = 0; i < collect.size(); i++) { - Column col = collect.get(i); - ColumnInfo columnInfo = data.get(i); - if (columnInfo.getIndex() != col.index) { - throw new SQLException("batch add column index not match, expected: " + columnInfo.getIndex() + ", actual: " + col.index); - } - if (columnInfo.getType() != col.type) { - throw new SQLException("batch add column type not match, expected type: " + columnInfo.getType() + ", actual type: " + col.type); - } - columnInfo.add(col.data); - } - } +// List collect = column.keySet().stream().sorted().map(column::get).collect(Collectors.toList()); +// if (data.isEmpty()) { +// for (Column col : collect) { +// data.add(new ColumnInfo(col.index, col.data, col.type)); +// } +// } else { +// if (collect.size() != data.size()) { +// throw new SQLException("batch add column size not match, expected: " + data.size() + ", actual: " + collect.size()); +// } +// +// for (int i = 0; i < collect.size(); i++) { +// Column col = collect.get(i); +// ColumnInfo columnInfo = data.get(i); +// if (columnInfo.getIndex() != col.index) { +// throw new SQLException("batch add column index not match, expected: " + columnInfo.getIndex() + ", actual: " + col.index); +// } +// if (columnInfo.getType() != col.type) { +// throw new SQLException("batch add column type not match, expected type: " + columnInfo.getType() + ", actual type: " + col.type); +// } +// columnInfo.add(col.data); +// } +// } } @Override public int[] executeBatch() throws SQLException { - if (column.isEmpty()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_BATCH_IS_EMPTY); - - //set tag - if (!tag.isEmpty()) { - List collect = tag.keySet().stream().sorted().map(i -> { - Column col = this.tag.get(i); - return new ColumnInfo(i, col.data, col.type); - }).collect(Collectors.toList()); - byte[] tagBlock; - try { - tagBlock = SerializeBlock.getRawBlock(collect, precision); - } catch (IOException e) { - throw new SQLException("data serialize error!", e); - } - Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.SET_TAGS.getAction(), - reqId, stmtId, BindType.TAG.get(), tagBlock); - if (Code.SUCCESS.getCode() != bindResp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); - } - } - // bind - byte[] rawBlock; - try { - rawBlock = SerializeBlock.getRawBlock(data, precision); - } catch (IOException e) { - throw new SQLException("data serialize error!", e); - } - Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.BIND.getAction(), - reqId, stmtId, BindType.BIND.get(), rawBlock); - if (Code.SUCCESS.getCode() != bindResp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); - } - - this.clearParameters(); - // send - Request request = RequestFactory.generateExec(stmtId, reqId); - ExecResp resp = (ExecResp) transport.send(request); - if (Code.SUCCESS.getCode() != resp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); - } - int[] ints = new int[resp.getAffected()]; - for (int i = 0, len = ints.length; i < len; i++) - ints[i] = SUCCESS_NO_INFO; - return ints; +// if (column.isEmpty()) +// throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_BATCH_IS_EMPTY); +// +// //set tag +// if (!tag.isEmpty()) { +// List collect = tag.keySet().stream().sorted().map(i -> { +// Column col = this.tag.get(i); +// return new ColumnInfo(i, col.data, col.type); +// }).collect(Collectors.toList()); +// byte[] tagBlock; +// try { +// tagBlock = SerializeBlock.getRawBlock(collect, precision); +// } catch (IOException e) { +// throw new SQLException("data serialize error!", e); +// } +// Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.SET_TAGS.getAction(), +// reqId, stmtId, BindType.TAG.get(), tagBlock); +// if (Code.SUCCESS.getCode() != bindResp.getCode()) { +// throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); +// } +// } +// // bind +// byte[] rawBlock; +// try { +// rawBlock = SerializeBlock.getRawBlock(data, precision); +// } catch (IOException e) { +// throw new SQLException("data serialize error!", e); +// } +// Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.BIND.getAction(), +// reqId, stmtId, BindType.BIND.get(), rawBlock); +// if (Code.SUCCESS.getCode() != bindResp.getCode()) { +// throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); +// } +// +// this.clearParameters(); +// // send +// Request request = RequestFactory.generateExec(stmtId, reqId); +// ExecResp resp = (ExecResp) transport.send(request); +// if (Code.SUCCESS.getCode() != resp.getCode()) { +// throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); +// } +// int[] ints = new int[resp.getAffected()]; +// for (int i = 0, len = ints.length; i < len; i++) +// ints[i] = SUCCESS_NO_INFO; +// return ints; + return null; } @Override @@ -703,22 +746,25 @@ public ResultSetMetaData getMetaData() throws SQLException { @Override public ParameterMetaData getParameterMetaData() throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - List list = new ArrayList<>(); - if (!tag.isEmpty()) { - tag.keySet().stream().sorted().forEach(i -> { - Column col = this.tag.get(i); - list.add(col.data); - }); - } - if (!column.isEmpty()) { - column.keySet().stream().sorted().forEach(i -> { - Column col = this.column.get(i); - list.add(col.data); - }); - } - return new TSDBParameterMetaData(list.toArray(new Object[0])); +// if (isClosed()) +// throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); +// List list = new ArrayList<>(); +// if (!tag.isEmpty()) { +// tag.keySet().stream().sorted().forEach(i -> { +// Column col = this.tag.get(i); +// list.add(col.data); +// }); +// } +// if (!column.isEmpty()) { +// column.keySet().stream().sorted().forEach(i -> { +// Column col = this.column.get(i); +// list.add(col.data); +// }); +// } +// return new TSDBParameterMetaData(list.toArray(new Object[0])); + + + return null; } @Override @@ -884,14 +930,17 @@ public Column(Object data, int type, int index) { } } + @Override public void setInt(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_INT, Integer.BYTES); } + @Override public void setFloat(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_FLOAT, Float.BYTES); } + @Override public void setTimestamp(int columnIndex, List list) throws SQLException { List collect = list.stream().map(x -> { if (x == null) { @@ -902,10 +951,12 @@ public void setTimestamp(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, collect, TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP, Long.BYTES); } + @Override public void setLong(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_BIGINT, Long.BYTES); } + @Override public void setDouble(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_DOUBLE, Double.BYTES); } @@ -914,14 +965,17 @@ public void setBoolean(int columnIndex, List list) throws SQLException setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_BOOL, Byte.BYTES); } + @Override public void setByte(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_TINYINT, Byte.BYTES); } + @Override public void setShort(int columnIndex, List list) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_SMALLINT, Short.BYTES); } + @Override public void setString(int columnIndex, List list, int size) throws SQLException { List collect = list.stream().map(x -> { if (x == null) { @@ -931,14 +985,16 @@ public void setString(int columnIndex, List list, int size) throws SQLEx }).collect(Collectors.toList()); setValueImpl(columnIndex, collect, TSDBConstants.TSDB_DATA_TYPE_BINARY, size); } - + @Override public void setVarbinary(int columnIndex, List list, int size) throws SQLException { setValueImpl(columnIndex, list, TSDB_DATA_TYPE_VARBINARY, size); } + @Override public void setGeometry(int columnIndex, List list, int size) throws SQLException { setValueImpl(columnIndex, list, TSDB_DATA_TYPE_GEOMETRY, size); } // note: expand the required space for each NChar character + @Override public void setNString(int columnIndex, List list, int size) throws SQLException { setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_NCHAR, size * Integer.BYTES); } @@ -951,40 +1007,32 @@ public void setValueImpl(int columnIndex, List list, int type, int bytes) queue.add(p); } + @Override public void columnDataAddBatch() throws SQLException { + while (!tag.isEmpty()){ + tableInfo.getTagInfo().add(tag.poll()); + } while (!queue.isEmpty()) { - data.add(queue.poll()); + tableInfo.getDataList().add(queue.poll()); } + tableInfoList.add(tableInfo); + tableInfo = TableInfo.getEmptyTableInfo(); } + @Override public void columnDataExecuteBatch() throws SQLException { - //set tag - if (!tag.isEmpty()) { - List collect = tag.keySet().stream().sorted().map(i -> { - Column col = this.tag.get(i); - return new ColumnInfo(i, col.data, col.type); - }).collect(Collectors.toList()); - byte[] tagBlock; - try { - tagBlock = SerializeBlock.getRawBlock(collect, precision); - } catch (IOException e) { - throw new SQLException("data serialize error!", e); - } - Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.SET_TAGS.getAction(), - reqId, stmtId, BindType.TAG.get(), tagBlock); - if (Code.SUCCESS.getCode() != bindResp.getCode()) { - throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); - } + if (tableInfoList.isEmpty()) { + throw new SQLException("batch data is empty"); } - // bind + byte[] rawBlock; try { - rawBlock = SerializeBlock.getRawBlock(data, precision); + rawBlock = SerializeBlock.getStmt2BindBlock(reqId, stmtId, tableInfoList, toBeBindTableNameCount, toBeBindTagCount, toBeBindColCount, precision); } catch (IOException e) { throw new SQLException("data serialize error!", e); } - Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.BIND.getAction(), - reqId, stmtId, BindType.BIND.get(), rawBlock); + Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.STMT2_BIND.getAction(), + reqId, rawBlock); if (Code.SUCCESS.getCode() != bindResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); } @@ -1001,4 +1049,20 @@ public void columnDataExecuteBatch() throws SQLException { public void columnDataCloseBatch() throws SQLException { this.close(); } + + + + + @Override + public void setTableName(String name) throws SQLException { + this.tableInfo.setTableName(name); + } + + private void ensureTagCapacity(int index) { + if (this.tableInfo.getTagInfo().size() < index + 1) { + int delta = index + 1 - this.tableInfo.getTagInfo().size(); + this.tableInfo.getTagInfo().addAll(Collections.nCopies(delta, null)); + } + } + } diff --git a/src/main/java/com/taosdata/jdbc/ws/Transport.java b/src/main/java/com/taosdata/jdbc/ws/Transport.java index 4b8041c8..d244d9a1 100644 --- a/src/main/java/com/taosdata/jdbc/ws/Transport.java +++ b/src/main/java/com/taosdata/jdbc/ws/Transport.java @@ -195,7 +195,7 @@ public Response send(String action, long reqId, long resultId, long type, byte[] throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED, "Websocket Not Connected Exception"); } - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(24 + rawData.length + rawData2.length); try { buffer.write(SerializeBlock.longToBytes(reqId)); buffer.write(SerializeBlock.longToBytes(resultId)); @@ -238,6 +238,46 @@ public Response send(String action, long reqId, long resultId, long type, byte[] } return response; } + + public Response send(String action, long reqId, byte[] buffer) throws SQLException { + if (isClosed()){ + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED, "Websocket Not Connected Exception"); + } + + + Response response; + CompletableFuture completableFuture = new CompletableFuture<>(); + try { + inFlightRequest.put(new FutureResponse(action, reqId, completableFuture)); + } catch (InterruptedException | TimeoutException e) { + throw new SQLException(e); + } + + try { + clientArr.get(currentNodeIndex).send(buffer); + } catch (WebsocketNotConnectedException e) { + tmqRethrowConnectionCloseException(); + reconnect(); + try { + clientArr.get(currentNodeIndex).send(buffer); + }catch (Exception ex){ + inFlightRequest.remove(action, reqId); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESTFul_Client_IOException, e.getMessage()); + } + } + + String reqString = "action:" + action + ", reqId:" + reqId; + CompletableFuture responseFuture = CompletableFutureTimeout.orTimeout(completableFuture, timeout, TimeUnit.MILLISECONDS, reqString); + try { + response = responseFuture.get(); + handleErrInMasterSlaveMode(response); + } catch (InterruptedException | ExecutionException e) { + inFlightRequest.remove(action, reqId); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_QUERY_TIMEOUT, e.getMessage()); + } + return response; + } + private void handleErrInMasterSlaveMode(Response response) throws InterruptedException{ if (clientArr.size() > 1 && response instanceof CommonResp){ CommonResp commonResp = (CommonResp) response; diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java index ec540097..456a5784 100644 --- a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java @@ -5,13 +5,18 @@ import com.taosdata.jdbc.utils.UInt64Deserializer; import com.taosdata.jdbc.ws.entity.CommonResp; +import java.util.List; + // init | prepare | set_table_name | set_tags | bind | add_batch public class Stmt2Resp extends CommonResp { @JsonProperty("stmt_id") @JsonDeserialize(using = UInt64Deserializer.class) private long stmtId; - - + private List fields; + @JsonProperty("fields_count") + private int fieldsCount; + @JsonProperty("is_insert") + private boolean isInsert; public long getStmtId() { return stmtId; } @@ -20,4 +25,27 @@ public void setStmtId(long stmtId) { this.stmtId = stmtId; } + public List getFields() { + return fields; + } + + public void setFields(List fields) { + this.fields = fields; + } + + public int getFieldsCount() { + return fieldsCount; + } + + public void setFieldsCount(int fieldsCount) { + this.fieldsCount = fieldsCount; + } + public boolean isInsert() { + return isInsert; + } + + public void setInsert(boolean insert) { + isInsert = insert; + } + } From cbe8867ff3dc5078170a3321a5535b43c610ce43 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Sat, 2 Nov 2024 17:52:12 +0800 Subject: [PATCH 04/15] add stmt2 support --- .../com/taosdata/jdbc/AbstractDriver.java | 1 + .../taosdata/jdbc/TaosPrepareStatement.java | 65 +++++++++++ .../com/taosdata/jdbc/common/ColumnInfo.java | 12 +- .../taosdata/jdbc/common/SerializeBlock.java | 93 ++++++++++++---- .../taosdata/jdbc/enums/FeildBindType.java | 27 +++++ .../jdbc/ws/TSWSPreparedStatement.java | 6 +- .../com/taosdata/jdbc/ws/entity/Action.java | 10 +- .../taosdata/jdbc/ws/stmt2/entity/Field.java | 2 +- .../{ExecResp.java => Stmt2ExecResp.java} | 2 +- ...PrepareResp.java => Stmt2PrepareResp.java} | 2 +- .../jdbc/ws/stmt2/entity/Stmt2Resp.java | 29 ----- .../jdbc/ws/WSPreparedStatementStmt2Test.java | 105 ++++++++++++++++++ 12 files changed, 285 insertions(+), 69 deletions(-) create mode 100644 src/main/java/com/taosdata/jdbc/TaosPrepareStatement.java create mode 100644 src/main/java/com/taosdata/jdbc/enums/FeildBindType.java rename src/main/java/com/taosdata/jdbc/ws/stmt2/entity/{ExecResp.java => Stmt2ExecResp.java} (93%) rename src/main/java/com/taosdata/jdbc/ws/stmt2/entity/{PrepareResp.java => Stmt2PrepareResp.java} (95%) create mode 100644 src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementStmt2Test.java diff --git a/src/main/java/com/taosdata/jdbc/AbstractDriver.java b/src/main/java/com/taosdata/jdbc/AbstractDriver.java index 1d4f5d30..0799d1df 100644 --- a/src/main/java/com/taosdata/jdbc/AbstractDriver.java +++ b/src/main/java/com/taosdata/jdbc/AbstractDriver.java @@ -74,6 +74,7 @@ protected Connection getWSConnection(String url, ConnectionParam param, Properti transport.setTextMessageHandler(message -> { try { + System.out.println("message = " + message); JsonNode jsonObject = JsonUtil.getObjectReader().readTree(message); Action action = Action.of(jsonObject.get("action").asText()); ObjectReader actionReader = JsonUtil.getObjectReader(action.getResponseClazz()); diff --git a/src/main/java/com/taosdata/jdbc/TaosPrepareStatement.java b/src/main/java/com/taosdata/jdbc/TaosPrepareStatement.java new file mode 100644 index 00000000..cf407f69 --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/TaosPrepareStatement.java @@ -0,0 +1,65 @@ +package com.taosdata.jdbc; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.List; + +public interface TaosPrepareStatement extends PreparedStatement { + + void setTableName(String name) throws SQLException; + + void setTagNull(int index, int type) throws SQLException; + + void setTagBoolean(int index, boolean value); + + void setTagByte(int index, byte value); + + void setTagShort(int index, short value); + + void setTagInt(int index, int value); + + void setTagLong(int index, long value); + + void setTagFloat(int index, float value); + + void setTagDouble(int index, double value); + + void setTagTimestamp(int index, long value); + + void setTagTimestamp(int index, Timestamp value); + + void setTagString(int index, String value); + + void setTagVarbinary(int index, byte[] value); + void setTagGeometry(int index, byte[] value); + + void setTagNString(int index, String value); + + void setTagJson(int index, String value); + void setInt(int columnIndex, List list) throws SQLException; + void setFloat(int columnIndex, List list) throws SQLException; + + void setTimestamp(int columnIndex, List list) throws SQLException; + + void setLong(int columnIndex, List list) throws SQLException; + + void setDouble(int columnIndex, List list) throws SQLException; + + void setBoolean(int columnIndex, List list) throws SQLException; + + void setByte(int columnIndex, List list) throws SQLException; + + void setShort(int columnIndex, List list) throws SQLException; + + void setString(int columnIndex, List list, int size) throws SQLException; + + void setVarbinary(int columnIndex, List list, int size) throws SQLException; + void setGeometry(int columnIndex, List list, int size) throws SQLException; + // note: expand the required space for each NChar character + void setNString(int columnIndex, List list, int size) throws SQLException; + + void columnDataAddBatch() throws SQLException; + + void columnDataExecuteBatch() throws SQLException; +} diff --git a/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java b/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java index 43840261..7274a9fc 100644 --- a/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java +++ b/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java @@ -13,13 +13,13 @@ public class ColumnInfo implements Comparable { private int serializeSize; - public ColumnInfo(int columnIndex, Object data, int type) { - this.index = columnIndex; - this.dataList.add(data); - this.type = type; - } +// public ColumnInfo(int columnIndex, Object data, int type) { +// this.index = columnIndex; +// this.dataList.add(data); +// this.type = type; +// } - public ColumnInfo(int columnIndex, List dataList, int type, Integer flag) { + public ColumnInfo(int columnIndex, List dataList, int type) { this.index = columnIndex; this.dataList = dataList; this.type = type; diff --git a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java index 12d149e9..81f0d560 100644 --- a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java +++ b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java @@ -102,6 +102,7 @@ private static int serializeColumn(ColumnInfo columnInfo, byte[] buf, int offset // data is array type buf[offset++] = 1; // length + int bufferLength = 0; for (Object o: columnInfo.getDataList()){ if (o == null){ SerializeInt(buf, offset, 0); @@ -114,13 +115,16 @@ private static int serializeColumn(ColumnInfo columnInfo, byte[] buf, int offset byte[] v = (byte[]) o; SerializeInt(buf, offset, v.length); offset += Integer.BYTES; + bufferLength += v.length; break; } case TSDB_DATA_TYPE_JSON: case TSDB_DATA_TYPE_NCHAR: { String v = (String) o; - SerializeInt(buf, offset, v.length()); + int len = v.getBytes().length; + SerializeInt(buf, offset, len); offset += Integer.BYTES; + bufferLength += len; break; } default: @@ -129,7 +133,11 @@ private static int serializeColumn(ColumnInfo columnInfo, byte[] buf, int offset } } - // Buffer + // buffer length + SerializeInt(buf, offset, bufferLength); + offset += Integer.BYTES; + + // buffer SerializeArrayDataType(columnInfo.getType(), buf, offset, columnInfo.getDataList()); return offset; } @@ -137,6 +145,9 @@ private static int serializeColumn(ColumnInfo columnInfo, byte[] buf, int offset private static void SerializeNormalDataType(int dataType , byte[] buf, int offset, List objectList, int precision) throws IOException, SQLException { switch (dataType) { case TSDB_DATA_TYPE_BOOL: { + SerializeInt(buf, offset, objectList.size()); + offset += Integer.BYTES; + for (Object o: objectList){ if (o == null) { buf[offset++] = 0; @@ -148,6 +159,9 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse break; } case TSDB_DATA_TYPE_TINYINT: { + SerializeInt(buf, offset, objectList.size()); + offset += Integer.BYTES; + for (Object o: objectList){ if (o == null) { buf[offset++] = 0; @@ -159,6 +173,9 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse break; } case TSDB_DATA_TYPE_SMALLINT: { + SerializeInt(buf, offset, objectList.size() * Short.BYTES); + offset += Integer.BYTES; + for (Object o: objectList){ short v = 0; if (o != null) { @@ -170,6 +187,9 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse break; } case TSDB_DATA_TYPE_INT: { + SerializeInt(buf, offset, objectList.size() * Integer.BYTES); + offset += Integer.BYTES; + for (Object o: objectList){ int v = 0; if (o != null) { @@ -181,6 +201,9 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse break; } case TSDB_DATA_TYPE_BIGINT: { + SerializeInt(buf, offset, objectList.size() * Long.BYTES); + offset += Integer.BYTES; + for (Object o: objectList){ long v = 0; if (o != null) { @@ -192,6 +215,9 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse break; } case TSDB_DATA_TYPE_FLOAT: { + SerializeInt(buf, offset, objectList.size() * Integer.BYTES); + offset += Integer.BYTES; + for (Object o: objectList){ float v = 0; if (o != null) { @@ -204,6 +230,9 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse break; } case TSDB_DATA_TYPE_DOUBLE: { + SerializeInt(buf, offset, objectList.size() * Long.BYTES); + offset += Integer.BYTES; + for (Object o: objectList){ double v = 0; if (o != null) { @@ -216,6 +245,9 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse break; } case TSDB_DATA_TYPE_TIMESTAMP: { + SerializeInt(buf, offset, objectList.size() * Long.BYTES); + offset += Integer.BYTES; + for (Object o: objectList){ if (o != null) { Timestamp t = (Timestamp) o; @@ -341,7 +373,7 @@ public static int getColumnSize(ColumnInfo column) throws SQLException { totalLength += v.length; } } - // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + 4 + v.length + totalLength + // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + 4 * v.length + totalLength return 17 + (5 * column.getDataList().size()) + totalLength; } case TSDB_DATA_TYPE_JSON: @@ -353,7 +385,7 @@ public static int getColumnSize(ColumnInfo column) throws SQLException { totalLength += v.length(); } } - // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + 4 + v.length + totalLength + // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + 4 * v.length + totalLength return 17 + (5 * column.getDataList().size()) + totalLength; } default: @@ -375,33 +407,39 @@ public static byte[] getStmt2BindBlock(long reqId, // cloc totol size int totalTableNameSize = 0; List tableNameSizeList = new ArrayList<>(); - for (int i = 0; i < tableInfoList.size(); i++) { - int tableNameSize = getTableNameTotalLength(tableInfoList, toBebindTableNameCount); - totalTableNameSize += tableNameSize; - tableNameSizeList.add((short)tableNameSize); + if (toBebindTableNameCount > 0) { + for (int i = 0; i < tableInfoList.size(); i++) { + int tableNameSize = getTableNameTotalLength(tableInfoList, toBebindTableNameCount); + totalTableNameSize += tableNameSize; + tableNameSizeList.add((short) tableNameSize); + } } - int totalagSize = 0; + int totaTagSize = 0; List tagSizeList = new ArrayList<>(); - - for (int i = 0; i < tableInfoList.size(); i++) { - int tagSize = getTagTotalLengthByTableIndex(tableInfoList, i, toBebindTagCount); - totalagSize += tagSize; - tagSizeList.add(tagSize); + if (toBebindTagCount > 0){ + for (int i = 0; i < tableInfoList.size(); i++) { + int tagSize = getTagTotalLengthByTableIndex(tableInfoList, i, toBebindTagCount); + totaTagSize += tagSize; + tagSizeList.add(tagSize); + } } + int totalColSize = 0; List colSizeList = new ArrayList<>(); - for (int i = 0; i < tableInfoList.size(); i++) { - int colSize = getColTotalLengthByTableIndex(tableInfoList, i, toBebindColCount); - totalColSize += colSize; - colSizeList.add(colSize); + if (toBebindColCount > 0) { + for (int i = 0; i < tableInfoList.size(); i++) { + int colSize = getColTotalLengthByTableIndex(tableInfoList, i, toBebindColCount); + totalColSize += colSize; + colSizeList.add(colSize); + } } - int totalSize = totalTableNameSize + totalagSize + totalColSize; + int totalSize = totalTableNameSize + totaTagSize + totalColSize; totalSize += tagSizeList.size() * (toBebindTableNameCount * Short.BYTES + toBebindTagCount * Integer.BYTES + toBebindColCount * Integer.BYTES); - byte[] buf = new byte[30 + totalSize]; + byte[] buf = new byte[58 + totalSize]; int offset = 0; //************ header ***************** @@ -425,7 +463,7 @@ public static byte[] getStmt2BindBlock(long reqId, //************ data ***************** // TotalLength - SerializeInt(buf, offset, totalSize); + SerializeInt(buf, offset, totalSize + 28); offset += Integer.BYTES; // tableCount @@ -472,7 +510,7 @@ public static byte[] getStmt2BindBlock(long reqId, } if (toBebindTagCount > 0){ - skipSize += totalagSize + Integer.BYTES * tableInfoList.size(); + skipSize += totaTagSize + Integer.BYTES * tableInfoList.size(); } SerializeInt(buf, offset, 28 + skipSize); offset += Integer.BYTES; @@ -507,7 +545,7 @@ public static byte[] getStmt2BindBlock(long reqId, if (toBebindTagCount > 0){ for (Integer tagsize: tagSizeList) { SerializeInt(buf, offset, tagsize); - offset += Integer.BYTES; + offset += Integer.BYTES; } for (int i = 0; i < tableInfoList.size(); i++) { @@ -521,7 +559,7 @@ public static byte[] getStmt2BindBlock(long reqId, } } - // TagsDataLength + // ColsDataLength if (toBebindColCount > 0){ for (Integer colSize: colSizeList) { SerializeInt(buf, offset, colSize); @@ -539,6 +577,13 @@ public static byte[] getStmt2BindBlock(long reqId, } } + + for (int i = 30; i < buf.length; i++) { + int bb = buf[i] & 0xff; + System.out.print(bb); + System.out.print(","); + } + System.out.println(); return buf; } diff --git a/src/main/java/com/taosdata/jdbc/enums/FeildBindType.java b/src/main/java/com/taosdata/jdbc/enums/FeildBindType.java new file mode 100644 index 00000000..1bc6fc3c --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/enums/FeildBindType.java @@ -0,0 +1,27 @@ +package com.taosdata.jdbc.enums; + +public enum FeildBindType { + TAOS_FIELD_COL(1), + TAOS_FIELD_TAG(2), + TAOS_FIELD_QUERY(3), + TAOS_FIELD_TBNAME(4); + + private final int value; + + FeildBindType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static FeildBindType fromValue(int value) { + for (FeildBindType field : FeildBindType.values()) { + if (field.value == value) { + return field; + } + } + throw new IllegalArgumentException("Unknown value: " + value); + } +} diff --git a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java index 526e96d6..89f15016 100644 --- a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java +++ b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java @@ -69,7 +69,7 @@ public TSWSPreparedStatement(Transport transport, ConnectionParam param, String } stmtId = resp.getStmtId(); Request prepare = RequestFactory.generatePrepare(stmtId, reqId, sql); - Stmt2Resp prepareResp = (Stmt2Resp) transport.send(prepare); + Stmt2PrepareResp prepareResp = (Stmt2PrepareResp) transport.send(prepare); if (Code.SUCCESS.getCode() != prepareResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(prepareResp.getCode()) + "):" + prepareResp.getMessage()); } @@ -1003,7 +1003,7 @@ public void setValueImpl(int columnIndex, List list, int type, int bytes) List listObject = list.stream() .map(Object.class::cast) .collect(Collectors.toList()); - ColumnInfo p = new ColumnInfo(columnIndex, listObject, type, null); + ColumnInfo p = new ColumnInfo(columnIndex, listObject, type); queue.add(p); } @@ -1040,7 +1040,7 @@ public void columnDataExecuteBatch() throws SQLException { this.clearParameters(); // send Request request = RequestFactory.generateExec(stmtId, reqId); - ExecResp resp = (ExecResp) transport.send(request); + Stmt2ExecResp resp = (Stmt2ExecResp) transport.send(request); if (Code.SUCCESS.getCode() != resp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); } diff --git a/src/main/java/com/taosdata/jdbc/ws/entity/Action.java b/src/main/java/com/taosdata/jdbc/ws/entity/Action.java index 33616e9c..9c4e5793 100644 --- a/src/main/java/com/taosdata/jdbc/ws/entity/Action.java +++ b/src/main/java/com/taosdata/jdbc/ws/entity/Action.java @@ -3,6 +3,8 @@ import com.taosdata.jdbc.ws.stmt.entity.ExecResp; import com.taosdata.jdbc.ws.stmt.entity.GetColFieldsResp; import com.taosdata.jdbc.ws.stmt.entity.StmtResp; +import com.taosdata.jdbc.ws.stmt2.entity.Stmt2ExecResp; +import com.taosdata.jdbc.ws.stmt2.entity.Stmt2PrepareResp; import com.taosdata.jdbc.ws.stmt2.entity.Stmt2Resp; import com.taosdata.jdbc.ws.tmq.entity.FetchRawBlockResp; @@ -38,11 +40,11 @@ public enum Action { // stmt2 STMT2_INIT("stmt2_init", Stmt2Resp.class), - STMT2_PREPARE("stmt2_prepare", Stmt2Resp.class), - STMT2_BIND("bind", Stmt2Resp.class), - STMT2_EXEC("exec", ExecResp.class), + STMT2_PREPARE("stmt2_prepare", Stmt2PrepareResp.class), + STMT2_BIND("stmt2_bind", Stmt2Resp.class), + STMT2_EXEC("stmt2_exec", Stmt2ExecResp.class), // response means nothing - STMT2_CLOSE("close", StmtResp.class), + STMT2_CLOSE("stmt2_close", Stmt2Resp.class), //schemaless INSERT("insert", CommonResp.class), diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java index 6d62b41c..3decf04d 100644 --- a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java @@ -10,7 +10,7 @@ public class Field { private byte scale; private int bytes; - @JsonProperty("bind_type") + @JsonProperty("BindType") private byte bindType; public String getName() { return name; diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecResp.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2ExecResp.java similarity index 93% rename from src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecResp.java rename to src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2ExecResp.java index 9fb6fdbb..e6942376 100644 --- a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ExecResp.java +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2ExecResp.java @@ -5,7 +5,7 @@ import com.taosdata.jdbc.utils.UInt64Deserializer; import com.taosdata.jdbc.ws.entity.CommonResp; -public class ExecResp extends CommonResp { +public class Stmt2ExecResp extends CommonResp { @JsonProperty("stmt_id") @JsonDeserialize(using = UInt64Deserializer.class) private long stmtId; diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareResp.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2PrepareResp.java similarity index 95% rename from src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareResp.java rename to src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2PrepareResp.java index e5ccacb8..2d0d36c5 100644 --- a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/PrepareResp.java +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2PrepareResp.java @@ -7,7 +7,7 @@ import java.util.List; -public class PrepareResp extends CommonResp { +public class Stmt2PrepareResp extends CommonResp { @JsonProperty("stmt_id") @JsonDeserialize(using = UInt64Deserializer.class) private long stmtId; diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java index 456a5784..c1a3be08 100644 --- a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Stmt2Resp.java @@ -12,11 +12,6 @@ public class Stmt2Resp extends CommonResp { @JsonProperty("stmt_id") @JsonDeserialize(using = UInt64Deserializer.class) private long stmtId; - private List fields; - @JsonProperty("fields_count") - private int fieldsCount; - @JsonProperty("is_insert") - private boolean isInsert; public long getStmtId() { return stmtId; } @@ -24,28 +19,4 @@ public long getStmtId() { public void setStmtId(long stmtId) { this.stmtId = stmtId; } - - public List getFields() { - return fields; - } - - public void setFields(List fields) { - this.fields = fields; - } - - public int getFieldsCount() { - return fieldsCount; - } - - public void setFieldsCount(int fieldsCount) { - this.fieldsCount = fieldsCount; - } - public boolean isInsert() { - return isInsert; - } - - public void setInsert(boolean insert) { - isInsert = insert; - } - } diff --git a/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementStmt2Test.java b/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementStmt2Test.java new file mode 100644 index 00000000..413619b2 --- /dev/null +++ b/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementStmt2Test.java @@ -0,0 +1,105 @@ +package com.taosdata.jdbc.ws; + +import com.taosdata.jdbc.TSDBPreparedStatement; +import com.taosdata.jdbc.utils.SpecifyAddress; +import org.junit.*; + +import java.sql.*; +import java.util.*; +import java.util.Random; + +@FixMethodOrder +public class WSPreparedStatementStmt2Test { + String host = "127.0.0.1"; + String db_name = "ws_prepare"; + String tableName = "wpt"; + String superTable = "wpt_st"; + Connection connection; + + int numOfSubTable = 1; + int numOfRow = 10; + private static final Random random = new Random(System.currentTimeMillis()); + + @Test + public void testStmt2Insert() throws SQLException { + String sql = "INSERT INTO sub1 USING " + db_name + "." + tableName + " TAGS(?,?) VALUES (?,?,?,?)"; + + try (TSWSPreparedStatement pstmt = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class)) { + + for (int i = 1; i <= numOfSubTable; i++) { + // set table name + //pstmt.setTableName("d_bind_" + i); + + // set tags + pstmt.setTagInt(0, i); + pstmt.setTagString(1, "location_" + i); + + // set column ts + ArrayList tsList = new ArrayList<>(); + long current = System.currentTimeMillis(); + for (int j = 0; j < numOfRow; j++) + tsList.add(current + j); + pstmt.setTimestamp(0, tsList); + + // set column current + ArrayList currentList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + currentList.add(random.nextFloat() * 30); + pstmt.setFloat(1, currentList); + + // set column voltage + ArrayList voltageList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + voltageList.add(random.nextInt(300)); + pstmt.setInt(2, voltageList); + + // set column phase + ArrayList phaseList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + phaseList.add(random.nextFloat()); + pstmt.setFloat(3, phaseList); + // add column + pstmt.columnDataAddBatch(); + } + // execute column + pstmt.columnDataExecuteBatch(); + // you can check exeResult here + System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); + } catch (Exception ex) { + // please refer to the JDBC specifications for detailed exceptions info + System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", + ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", + ex.getMessage()); + // Print stack trace for context in examples. Use logging in production. + ex.printStackTrace(); + throw ex; + } + } + + + @Before + public void before() throws SQLException { + String url = SpecifyAddress.getInstance().getWebSocketWithoutUrl(); + if (url == null) { + url = "jdbc:TAOS-WS://" + host + ":6041/?user=root&password=taosdata"; + } else { + url += "?user=root&password=taosdata&batchfetch=true"; + } + Properties properties = new Properties(); + connection = DriverManager.getConnection(url, properties); + Statement statement = connection.createStatement(); + statement.execute("drop database if exists " + db_name); + statement.execute("create database " + db_name); + statement.execute("use " + db_name); + statement.execute("create stable if not exists " + db_name + "." + tableName + " (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); + statement.close(); + } + + @After + public void after() throws SQLException { + try (Statement statement = connection.createStatement()) { + statement.execute("drop database if exists " + db_name); + } + connection.close(); + } +} From 16cc6972632960f8dac9ce83b39a274a959c9519 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Wed, 6 Nov 2024 17:55:10 +0800 Subject: [PATCH 05/15] support std jdbc stmt api --- .../com/taosdata/jdbc/common/ColumnInfo.java | 2 +- .../taosdata/jdbc/common/SerializeBlock.java | 34 +- .../jdbc/ws/TSWSPreparedStatement.java | 374 +++++++++--------- .../taosdata/jdbc/ws/stmt2/entity/Field.java | 2 +- .../jdbc/ws/TSWSPreparedStatementTest.java | 7 +- 5 files changed, 211 insertions(+), 208 deletions(-) diff --git a/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java b/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java index 7274a9fc..854e8a1f 100644 --- a/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java +++ b/src/main/java/com/taosdata/jdbc/common/ColumnInfo.java @@ -4,7 +4,7 @@ import java.util.List; public class ColumnInfo implements Comparable { - private List dataList = new ArrayList<>(); + private List dataList; // taos data type private final int type; private final int index; diff --git a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java index 81f0d560..9e94a376 100644 --- a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java +++ b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java @@ -304,9 +304,9 @@ private static void SerializeArrayDataType(int dataType , byte[] buf, int offset throw new SQLException("unsupported data type : " + dataType); } } - public static int getTableNameTotalLength(List tableInfoList, int toBebindTableNameCount) throws SQLException{ + public static int getTableNameTotalLength(List tableInfoList, int toBeBindTableNameIndex) throws SQLException{ int totalLength = 0; - if (toBebindTableNameCount > 0){ + if (toBeBindTableNameIndex >= 0){ for ( TableInfo tableInfo: tableInfoList){ if (StringUtils.isEmpty(tableInfo.getTableName())) { throw new SQLException("table name is empty"); @@ -343,9 +343,6 @@ public static int getColTotalLengthByTableIndex(List tableInfoList, i } for (ColumnInfo columnInfo : tableInfoList.get(index).getDataList()){ - if (columnInfo.getDataList().get(index) == null){ - throw new SQLException("col value is null, index: " + index); - } int columnSize = getColumnSize(columnInfo); columnInfo.setSerializeSize(columnSize); totalLength += columnSize; @@ -382,7 +379,7 @@ public static int getColumnSize(ColumnInfo column) throws SQLException { for (Object o : column.getDataList()) { if (o != null) { String v = (String) o; - totalLength += v.length(); + totalLength += v.getBytes().length; } } // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + 4 * v.length + totalLength @@ -399,7 +396,7 @@ public static int getColumnSize(ColumnInfo column) throws SQLException { public static byte[] getStmt2BindBlock(long reqId, long stmtId, List tableInfoList, - int toBebindTableNameCount, + int toBeBindTableNameIndex, int toBebindTagCount, int toBebindColCount, int precision) throws IOException, SQLException { @@ -407,20 +404,20 @@ public static byte[] getStmt2BindBlock(long reqId, // cloc totol size int totalTableNameSize = 0; List tableNameSizeList = new ArrayList<>(); - if (toBebindTableNameCount > 0) { + if (toBeBindTableNameIndex >= 0) { for (int i = 0; i < tableInfoList.size(); i++) { - int tableNameSize = getTableNameTotalLength(tableInfoList, toBebindTableNameCount); + int tableNameSize = getTableNameTotalLength(tableInfoList, toBeBindTableNameIndex); totalTableNameSize += tableNameSize; tableNameSizeList.add((short) tableNameSize); } } - int totaTagSize = 0; + int totalTagSize = 0; List tagSizeList = new ArrayList<>(); if (toBebindTagCount > 0){ for (int i = 0; i < tableInfoList.size(); i++) { int tagSize = getTagTotalLengthByTableIndex(tableInfoList, i, toBebindTagCount); - totaTagSize += tagSize; + totalTagSize += tagSize; tagSizeList.add(tagSize); } } @@ -436,8 +433,13 @@ public static byte[] getStmt2BindBlock(long reqId, } } - int totalSize = totalTableNameSize + totaTagSize + totalColSize; - totalSize += tagSizeList.size() * (toBebindTableNameCount * Short.BYTES + toBebindTagCount * Integer.BYTES + toBebindColCount * Integer.BYTES); + int totalSize = totalTableNameSize + totalTagSize + totalColSize; + int toBebindTableNameCount = toBeBindTableNameIndex >= 0 ? 1 : 0; + + totalSize += tableInfoList.size() * ( + toBebindTableNameCount * Short.BYTES + + (toBebindTagCount > 0 ? 1 : 0) * Integer.BYTES + + (toBebindColCount > 0 ? 1 : 0) * Integer.BYTES); byte[] buf = new byte[58 + totalSize]; int offset = 0; @@ -479,7 +481,6 @@ public static byte[] getStmt2BindBlock(long reqId, offset += Integer.BYTES; // tableNameOffset - int totalTableNameOffset = 0; if (toBebindTableNameCount > 0){ SerializeInt(buf, offset, 0x1C); offset += Integer.BYTES; @@ -510,7 +511,7 @@ public static byte[] getStmt2BindBlock(long reqId, } if (toBebindTagCount > 0){ - skipSize += totaTagSize + Integer.BYTES * tableInfoList.size(); + skipSize += totalTagSize + Integer.BYTES * tableInfoList.size(); } SerializeInt(buf, offset, 28 + skipSize); offset += Integer.BYTES; @@ -568,9 +569,6 @@ public static byte[] getStmt2BindBlock(long reqId, for (int i = 0; i < tableInfoList.size(); i++) { for (ColumnInfo col : tableInfoList.get(i).getDataList()){ - if (col.getDataList().get(i) == null){ - throw new SQLException("tag value is null, index: " + i); - } serializeColumn(col, buf, offset, precision); offset += col.getSerializeSize(); } diff --git a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java index 89f15016..e8513c72 100644 --- a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java +++ b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java @@ -8,6 +8,7 @@ import com.taosdata.jdbc.enums.TimestampPrecision; import com.taosdata.jdbc.rs.ConnectionParam; import com.taosdata.jdbc.utils.ReqId; +import com.taosdata.jdbc.utils.StringUtils; import com.taosdata.jdbc.utils.Utils; import com.taosdata.jdbc.ws.entity.Action; import com.taosdata.jdbc.ws.entity.Code; @@ -38,14 +39,14 @@ public class TSWSPreparedStatement extends WSStatement implements TaosPrepareSta private int queryTimeout = 0; private int precision = TimestampPrecision.MS; - private int toBeBindTableNameCount = 0; + private int toBeBindTableNameIndex = -1; private int toBeBindColCount = 0; private int toBeBindTagCount = 0; private List fields; private boolean isInsert = false; - private final Map column = new HashMap<>(); + private final Map column = new TreeMap<>(); private final PriorityQueue tag = new PriorityQueue<>(); private final PriorityQueue queue = new PriorityQueue<>(); @@ -74,30 +75,26 @@ public TSWSPreparedStatement(Transport transport, ConnectionParam param, String throw new SQLException("(0x" + Integer.toHexString(prepareResp.getCode()) + "):" + prepareResp.getMessage()); } -// if (prepareResp.getFieldsCount() != prepareResp.getFields().size()){ -// throw new SQLException("prepare error: fields count not match"); -// } - isInsert = prepareResp.isInsert(); if (isInsert){ fields = prepareResp.getFields(); - for (Field field : fields){ + if (!fields.isEmpty()){ + precision = fields.get(0).getPrecision(); + } + for (int i = 0; i < fields.size(); i++){ + Field field = fields.get(i); if (field.getBindType() == FeildBindType.TAOS_FIELD_TBNAME.getValue()){ - toBeBindTableNameCount++; + toBeBindTableNameIndex = i; } if (field.getBindType() == FeildBindType.TAOS_FIELD_TAG.getValue()){ - toBeBindTagCount ++; + toBeBindTagCount++; } if (field.getBindType() == FeildBindType.TAOS_FIELD_COL.getValue()){ - toBeBindColCount ++; + toBeBindColCount++; } } } else if (!isInsert && prepareResp.getFieldsCount() > 0){ - for (Field field : fields){ - if (field.getBindType() == FeildBindType.TAOS_FIELD_QUERY.getValue()){ - toBeBindColCount ++; - } - } + toBeBindColCount = prepareResp.getFieldsCount(); } else { return; } @@ -141,81 +138,50 @@ public boolean execute(String sql, Long reqId) throws SQLException { @Override public ResultSet executeQuery() throws SQLException { -// List list = new ArrayList<>(); -// if (!tag.isEmpty()) { -// tag.keySet().stream().sorted().forEach(i -> { -// Column col = this.tag.get(i); -// list.add(col.data); -// }); -// } -// if (!column.isEmpty()) { -// column.keySet().stream().sorted().forEach(i -> { -// Column col = this.column.get(i); -// list.add(col.data); -// }); -// } -// Object[] parameters = list.toArray(new Object[0]); -// this.clearParameters(); -// -// final String sql = Utils.getNativeSql(this.rawSql, parameters); -// return executeQuery(sql); - - - return null; + List list = new ArrayList<>(); + + while (!tag.isEmpty()){ + ColumnInfo columnInfo = tag.poll(); + if (columnInfo.getDataList().size() != 1){ + throw new SQLException("tag size is not equal 1"); + } + + list.add(columnInfo.getDataList().get(0)); + } + + if (!column.isEmpty()) { + column.keySet().stream().sorted().forEach(i -> { + Column col = this.column.get(i); + list.add(col.data); + }); + } + Object[] parameters = list.toArray(new Object[0]); + this.clearParameters(); + + final String sql = Utils.getNativeSql(this.rawSql, parameters); + return executeQuery(sql); } @Override public int executeUpdate() throws SQLException { -// if (column.isEmpty()) -// throw new SQLException("no parameter to execute"); -// if (!data.isEmpty()) -// throw TSDBError.undeterminedExecutionError(); -// -// //set tag -// if (!tag.isEmpty()) { -// List collect = tag.keySet().stream().sorted().map(i -> { -// Column col = this.tag.get(i); -// return new ColumnInfo(i, col.data, col.type); -// }).collect(Collectors.toList()); -// byte[] tagBlock; -// try { -// tagBlock = SerializeBlock.getRawBlock(collect, precision); -// } catch (IOException e) { -// throw new SQLException("data serialize error!", e); -// } -// Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.SET_TAGS.getAction(), -// reqId, stmtId, BindType.TAG.get(), tagBlock); -// if (Code.SUCCESS.getCode() != bindResp.getCode()) { -// throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); -// } -// } -// // bind -// List collect = column.keySet().stream().sorted().map(i -> { -// Column col = this.column.get(i); -// return new ColumnInfo(i, col.data, col.type); -// }).collect(Collectors.toList()); -// byte[] rawBlock; -// try { -// rawBlock = SerializeBlock.getRawBlock(collect, precision); -// } catch (IOException e) { -// throw new SQLException("data serialize error!", e); -// } -// Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.BIND.getAction(), -// reqId, stmtId, BindType.BIND.get(), rawBlock); -// if (Code.SUCCESS.getCode() != bindResp.getCode()) { -// throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); -// } -// this.clearParameters(); -// // send -// Request request = RequestFactory.generateExec(stmtId, reqId); -// ExecResp resp = (ExecResp) transport.send(request); -// if (Code.SUCCESS.getCode() != resp.getCode()) { -// throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage(), "P0001", resp.getCode()); -// } -// -// return resp.getAffected(); - - return 0; + if (column.isEmpty()) + throw new SQLException("no parameter to execute"); + if (!tableInfo.getDataList().isEmpty() || !tableInfo.getTagInfo().isEmpty()) + throw TSDBError.undeterminedExecutionError(); + + while (!tag.isEmpty()){ + tableInfo.getTagInfo().add(tag.poll()); + } + + for (Map.Entry entry : column.entrySet()) { + Column col = entry.getValue(); + tableInfo.getDataList().add(new ColumnInfo(entry.getKey(), Collections.singletonList(col.data), col.type)); + } + + tableInfoList.add(tableInfo); + + + return executeBatchImpl(); } // set sub-table name @@ -544,10 +510,9 @@ public void setBinaryStream(int parameterIndex, InputStream x, int length) throw public void clearParameters() throws SQLException { column.clear(); tag.clear(); + queue.clear(); - tableInfo.setTableName(""); - tableInfo.getTagInfo().clear(); - tableInfo.getDataList().clear(); + tableInfo = TableInfo.getEmptyTableInfo(); tableInfoList.clear(); } @@ -636,12 +601,14 @@ public boolean execute() throws SQLException { throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); List list = new ArrayList<>(); -// if (!tag.isEmpty()) { -// tag.keySet().stream().sorted().forEach(i -> { -// Column col = this.tag.get(i); -// list.add(col.data); -// }); -// } + while (!tag.isEmpty()){ + ColumnInfo columnInfo = tag.poll(); + if (columnInfo.getDataList().size() != 1){ + throw new SQLException("tag size is not equal 1"); + } + + list.add(columnInfo.getDataList().get(0)); + } if (!column.isEmpty()) { column.keySet().stream().sorted().forEach(i -> { Column col = this.column.get(i); @@ -654,80 +621,114 @@ public boolean execute() throws SQLException { return execute(sql); } + private void bindAllToTableInfo(){ + for (int index = 0; index < fields.size(); index++) { + if (fields.get(index).getBindType() == FeildBindType.TAOS_FIELD_TBNAME.getValue()) { + tableInfo.setTableName(column.get(index + 1).data.toString()); + } else if (fields.get(index).getBindType() == FeildBindType.TAOS_FIELD_TAG.getValue()) { + tableInfo.getTagInfo().add(new ColumnInfo(index, Collections.singletonList(column.get(index + 1).data), fields.get(index).getFieldType())); + } else if (fields.get(index).getBindType() == FeildBindType.TAOS_FIELD_COL.getValue()) { + tableInfo.getDataList().add(new ColumnInfo(index, Collections.singletonList(column.get(index + 1).data), fields.get(index).getFieldType())); + } + } + } + + private void bindColToTableInfo(){ + for (int index = 0; index < fields.size(); index++) { + if (fields.get(index).getBindType() == FeildBindType.TAOS_FIELD_COL.getValue()) { + tableInfo.getDataList().add(new ColumnInfo(index, Collections.singletonList(column.get(index + 1).data), fields.get(index).getFieldType())); + } + } + } + private void bindAll(){ + if (toBeBindTableNameIndex >= 0){ + if (tableInfo.getTableName().isEmpty()) { + // first time, bind all + bindAllToTableInfo(); + } else { + if (tableInfo.getTableName().equals(column.get(toBeBindTableNameIndex + 1).toString())){ + // same table, only bind col + bindColToTableInfo(); + } else { + // different table, flush tableInfo and create a new one + tableInfoList.add(tableInfo); + tableInfo = TableInfo.getEmptyTableInfo(); + bindAllToTableInfo(); + } + } + } else { + // must same table + if (toBeBindTagCount > 0 && tableInfo.getTagInfo().isEmpty()){ + // first time, bind all + bindAllToTableInfo(); + } else { + // only bind col + bindColToTableInfo(); + } + } + } + private void onlyBindCol() { + if (tableInfo.getDataList().isEmpty()){ + for (Map.Entry entry : column.entrySet()) { + Column col = entry.getValue(); + List list = new ArrayList<>(); + list.add(col.data); + tableInfo.getDataList().add(new ColumnInfo(entry.getKey(), list, col.type)); + } + } else { + for (Map.Entry entry : column.entrySet()) { + Column col = entry.getValue(); + tableInfo.getDataList().get(col.index - 1).add(col.data); + } + } + } + @Override + // Only support batch insert public void addBatch() throws SQLException { -// List collect = column.keySet().stream().sorted().map(column::get).collect(Collectors.toList()); -// if (data.isEmpty()) { -// for (Column col : collect) { -// data.add(new ColumnInfo(col.index, col.data, col.type)); -// } -// } else { -// if (collect.size() != data.size()) { -// throw new SQLException("batch add column size not match, expected: " + data.size() + ", actual: " + collect.size()); -// } -// -// for (int i = 0; i < collect.size(); i++) { -// Column col = collect.get(i); -// ColumnInfo columnInfo = data.get(i); -// if (columnInfo.getIndex() != col.index) { -// throw new SQLException("batch add column index not match, expected: " + columnInfo.getIndex() + ", actual: " + col.index); -// } -// if (columnInfo.getType() != col.type) { -// throw new SQLException("batch add column type not match, expected type: " + columnInfo.getType() + ", actual type: " + col.type); -// } -// columnInfo.add(col.data); -// } -// } + if (column.size() == toBeBindColCount){ + if (toBeBindTableNameIndex < 0 && toBeBindTagCount == 0) { + onlyBindCol(); + } else { + if (toBeBindTableNameIndex >= 0 && tableInfo.getTableName().isEmpty()){ + throw new SQLException("table name is empty"); + } + if (tableInfo.getTagInfo().size()!= toBeBindTagCount){ + throw new SQLException("tag size not match, expected: " + toBeBindTagCount + ", actual: " + tableInfo.getTagInfo().size()); + } + onlyBindCol(); + } + return; + } + + if (column.size() == fields.size()){ + // bind all + bindAll(); + return; + } + throw new SQLException("column size not match, expected: " + fields.size() + ", actual: " + column.size()); } + private boolean isTableInfoBinded(){ + if (StringUtils.isEmpty(tableInfo.getTableName()) && tableInfo.getTagInfo().isEmpty() && tableInfo.getDataList().isEmpty()){ + return false; + } + return true; + } @Override public int[] executeBatch() throws SQLException { -// if (column.isEmpty()) -// throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_BATCH_IS_EMPTY); -// -// //set tag -// if (!tag.isEmpty()) { -// List collect = tag.keySet().stream().sorted().map(i -> { -// Column col = this.tag.get(i); -// return new ColumnInfo(i, col.data, col.type); -// }).collect(Collectors.toList()); -// byte[] tagBlock; -// try { -// tagBlock = SerializeBlock.getRawBlock(collect, precision); -// } catch (IOException e) { -// throw new SQLException("data serialize error!", e); -// } -// Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.SET_TAGS.getAction(), -// reqId, stmtId, BindType.TAG.get(), tagBlock); -// if (Code.SUCCESS.getCode() != bindResp.getCode()) { -// throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); -// } -// } -// // bind -// byte[] rawBlock; -// try { -// rawBlock = SerializeBlock.getRawBlock(data, precision); -// } catch (IOException e) { -// throw new SQLException("data serialize error!", e); -// } -// Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.BIND.getAction(), -// reqId, stmtId, BindType.BIND.get(), rawBlock); -// if (Code.SUCCESS.getCode() != bindResp.getCode()) { -// throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); -// } -// -// this.clearParameters(); -// // send -// Request request = RequestFactory.generateExec(stmtId, reqId); -// ExecResp resp = (ExecResp) transport.send(request); -// if (Code.SUCCESS.getCode() != resp.getCode()) { -// throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); -// } -// int[] ints = new int[resp.getAffected()]; -// for (int i = 0, len = ints.length; i < len; i++) -// ints[i] = SUCCESS_NO_INFO; -// return ints; - return null; + if (column.isEmpty()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_BATCH_IS_EMPTY); + + if (isTableInfoBinded()){ + tableInfoList.add(tableInfo); + } + + int affected = executeBatchImpl(); + int[] ints = new int[affected]; + for (int i = 0, len = ints.length; i < len; i++) + ints[i] = SUCCESS_NO_INFO; + return ints; } @Override @@ -746,25 +747,24 @@ public ResultSetMetaData getMetaData() throws SQLException { @Override public ParameterMetaData getParameterMetaData() throws SQLException { -// if (isClosed()) -// throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); -// List list = new ArrayList<>(); -// if (!tag.isEmpty()) { -// tag.keySet().stream().sorted().forEach(i -> { -// Column col = this.tag.get(i); -// list.add(col.data); -// }); -// } -// if (!column.isEmpty()) { -// column.keySet().stream().sorted().forEach(i -> { -// Column col = this.column.get(i); -// list.add(col.data); -// }); -// } -// return new TSDBParameterMetaData(list.toArray(new Object[0])); - + if (isClosed()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); + List list = new ArrayList<>(); + while (!tag.isEmpty()){ + ColumnInfo columnInfo = tag.poll(); + if (columnInfo.getDataList().size() != 1){ + throw new SQLException("tag size is not equal 1"); + } - return null; + list.add(columnInfo.getDataList().get(0)); + } + if (!column.isEmpty()) { + column.keySet().stream().sorted().forEach(i -> { + Column col = this.column.get(i); + list.add(col.data); + }); + } + return new TSDBParameterMetaData(list.toArray(new Object[0])); } @Override @@ -1019,15 +1019,15 @@ public void columnDataAddBatch() throws SQLException { tableInfo = TableInfo.getEmptyTableInfo(); } - @Override - public void columnDataExecuteBatch() throws SQLException { + + private int executeBatchImpl() throws SQLException { if (tableInfoList.isEmpty()) { throw new SQLException("batch data is empty"); } byte[] rawBlock; try { - rawBlock = SerializeBlock.getStmt2BindBlock(reqId, stmtId, tableInfoList, toBeBindTableNameCount, toBeBindTagCount, toBeBindColCount, precision); + rawBlock = SerializeBlock.getStmt2BindBlock(reqId, stmtId, tableInfoList, toBeBindTableNameIndex, toBeBindTagCount, toBeBindColCount, precision); } catch (IOException e) { throw new SQLException("data serialize error!", e); } @@ -1044,6 +1044,12 @@ public void columnDataExecuteBatch() throws SQLException { if (Code.SUCCESS.getCode() != resp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); } + + return resp.getAffected(); + } + @Override + public void columnDataExecuteBatch() throws SQLException { + executeBatchImpl(); } public void columnDataCloseBatch() throws SQLException { diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java index 3decf04d..6d62b41c 100644 --- a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/Field.java @@ -10,7 +10,7 @@ public class Field { private byte scale; private int bytes; - @JsonProperty("BindType") + @JsonProperty("bind_type") private byte bindType; public String getName() { return name; diff --git a/src/test/java/com/taosdata/jdbc/ws/TSWSPreparedStatementTest.java b/src/test/java/com/taosdata/jdbc/ws/TSWSPreparedStatementTest.java index 46e6a699..a92c5330 100644 --- a/src/test/java/com/taosdata/jdbc/ws/TSWSPreparedStatementTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/TSWSPreparedStatementTest.java @@ -148,9 +148,9 @@ public void executeTest() throws SQLException { stmt.execute("drop table if exists weather_test"); stmt.execute("create table weather_test(ts timestamp, f1 nchar(4), f2 float, f3 double, f4 timestamp, f5 int, f6 bool, f7 binary(10))"); - TSWSPreparedStatement s = (TSWSPreparedStatement) conn.prepareStatement("insert into ? values(?, ?, ?, ?, ?, ?, ?, ?)"); + TSWSPreparedStatement s = (TSWSPreparedStatement) conn.prepareStatement("insert into weather_test values(?, ?, ?, ?, ?, ?, ?, ?)"); Random r = new Random(); - s.setTableName("weather_test"); + //s.setTableName("weather_test"); ArrayList ts = new ArrayList<>(); for (int i = 0; i < numOfRows; i++) { @@ -260,9 +260,8 @@ public void bindDataSelectColumnTest() throws SQLException { stmt.execute("drop table if exists weather_test"); stmt.execute("create table weather_test(ts timestamp, f1 nchar(4), f2 float, f3 double, f4 timestamp, f5 int, f6 bool, f7 binary(10))"); - TSWSPreparedStatement s = (TSWSPreparedStatement) conn.prepareStatement("insert into ? (ts, f1, f7) values(?, ?, ?)"); + TSWSPreparedStatement s = (TSWSPreparedStatement) conn.prepareStatement("insert into weather_test (ts, f1, f7) values(?, ?, ?)"); Random r = new Random(); - s.setTableName("weather_test"); ArrayList ts = new ArrayList<>(); for (int i = 0; i < numOfRows; i++) { From cb2d5569024d114098bdd358e6b80ca6bd5675d0 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Mon, 9 Dec 2024 11:53:05 +0800 Subject: [PATCH 06/15] remove old stmt implements --- .../taosdata/jdbc/ws/AbstractWSResultSet.java | 7 +- .../jdbc/ws/TSWSPreparedStatement.java | 88 ++++++++----------- .../com/taosdata/jdbc/ws/WSStatement.java | 4 +- .../com/taosdata/jdbc/ws/entity/Action.java | 17 +--- .../jdbc/ws/stmt/entity/AddBatchReq.java | 20 ----- .../taosdata/jdbc/ws/stmt/entity/BindReq.java | 29 ------ .../jdbc/ws/stmt/entity/CloseReq.java | 20 ----- .../taosdata/jdbc/ws/stmt/entity/ExecReq.java | 20 ----- .../jdbc/ws/stmt/entity/ExecResp.java | 28 ------ .../taosdata/jdbc/ws/stmt/entity/Field.java | 50 ----------- .../jdbc/ws/stmt/entity/GetColFieldsReq.java | 21 ----- .../jdbc/ws/stmt/entity/GetColFieldsResp.java | 30 ------- .../taosdata/jdbc/ws/stmt/entity/InitReq.java | 6 -- .../jdbc/ws/stmt/entity/PrepareReq.java | 29 ------ .../jdbc/ws/stmt/entity/RequestFactory.java | 79 ----------------- .../jdbc/ws/stmt/entity/SetTableNameReq.java | 29 ------ .../jdbc/ws/stmt/entity/SetTagReq.java | 29 ------ .../jdbc/ws/stmt/entity/StmtResp.java | 20 ----- .../jdbc/ws/stmt2/entity/BindReq.java | 29 ------ .../jdbc/ws/stmt2/entity/RequestFactory.java | 15 ++-- 20 files changed, 48 insertions(+), 522 deletions(-) delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/AddBatchReq.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/BindReq.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/CloseReq.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/ExecReq.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/ExecResp.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/Field.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/GetColFieldsReq.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/GetColFieldsResp.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/InitReq.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/PrepareReq.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/RequestFactory.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/SetTableNameReq.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/SetTagReq.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt/entity/StmtResp.java delete mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/BindReq.java diff --git a/src/main/java/com/taosdata/jdbc/ws/AbstractWSResultSet.java b/src/main/java/com/taosdata/jdbc/ws/AbstractWSResultSet.java index b528a981..c1049871 100644 --- a/src/main/java/com/taosdata/jdbc/ws/AbstractWSResultSet.java +++ b/src/main/java/com/taosdata/jdbc/ws/AbstractWSResultSet.java @@ -1,12 +1,13 @@ package com.taosdata.jdbc.ws; -import com.taosdata.jdbc.*; -import com.taosdata.jdbc.enums.BindType; +import com.taosdata.jdbc.AbstractResultSet; +import com.taosdata.jdbc.BlockData; +import com.taosdata.jdbc.TSDBError; +import com.taosdata.jdbc.TSDBErrorNumbers; import com.taosdata.jdbc.enums.DataType; import com.taosdata.jdbc.rs.RestfulResultSet; import com.taosdata.jdbc.rs.RestfulResultSetMetaData; import com.taosdata.jdbc.ws.entity.*; -import com.taosdata.jdbc.ws.stmt.entity.StmtResp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java index e8513c72..7812927c 100644 --- a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java +++ b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java @@ -93,26 +93,11 @@ public TSWSPreparedStatement(Transport transport, ConnectionParam param, String toBeBindColCount++; } } - } else if (!isInsert && prepareResp.getFieldsCount() > 0){ + } else if (prepareResp.getFieldsCount() > 0){ toBeBindColCount = prepareResp.getFieldsCount(); - } else { - return; } this.tableInfo = TableInfo.getEmptyTableInfo(); - - // now we know the number of fields, we can prepare the cache data - if (prepareResp.isInsert()){ -// for (int i = 0; i < toBeBindColCount; i++){ -// if (prepareResp.getFields().get(i).getType() == TSDB_DATA_TYPE_UNKNOWN){ -// column.put(i, new Column(null, TSDB_DATA_TYPE_UNKNOWN, i)); -// } -// column.put(i, new Column(null, TSDB_DATA_TYPE_UNKNOWN, i)); -// } - - } else { - - } } @Override @@ -138,49 +123,46 @@ public boolean execute(String sql, Long reqId) throws SQLException { @Override public ResultSet executeQuery() throws SQLException { - List list = new ArrayList<>(); + if (this.isInsert){ + throw new SQLException("The query SQL must be prepared."); + } - while (!tag.isEmpty()){ - ColumnInfo columnInfo = tag.poll(); - if (columnInfo.getDataList().size() != 1){ - throw new SQLException("tag size is not equal 1"); - } + if (isTableInfoEmpty()){ + return executeQuery(this.rawSql); + } - list.add(columnInfo.getDataList().get(0)); + if (!StringUtils.isEmpty(tableInfo.getTableName()) + || !tableInfo.getTagInfo().isEmpty()){ + throw new SQLException("only support bind columns."); } - if (!column.isEmpty()) { - column.keySet().stream().sorted().forEach(i -> { - Column col = this.column.get(i); - list.add(col.data); - }); + this.executeBatchImpl(); + + Request request = RequestFactory.generateUseResult(stmtId, reqId); + ResultResp resp = (ResultResp) transport.send(request); + if (Code.SUCCESS.getCode() != resp.getCode()) { + throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); } - Object[] parameters = list.toArray(new Object[0]); - this.clearParameters(); - final String sql = Utils.getNativeSql(this.rawSql, parameters); - return executeQuery(sql); + this.resultSet = new BlockResultSet(this, this.transport, resp, this.database); + this.affectedRows = -1; + return this.resultSet; } @Override public int executeUpdate() throws SQLException { - if (column.isEmpty()) - throw new SQLException("no parameter to execute"); - if (!tableInfo.getDataList().isEmpty() || !tableInfo.getTagInfo().isEmpty()) - throw TSDBError.undeterminedExecutionError(); - - while (!tag.isEmpty()){ - tableInfo.getTagInfo().add(tag.poll()); - } - for (Map.Entry entry : column.entrySet()) { - Column col = entry.getValue(); - tableInfo.getDataList().add(new ColumnInfo(entry.getKey(), Collections.singletonList(col.data), col.type)); + if (fields.isEmpty()){ + return this.executeUpdate(this.rawSql); } - tableInfoList.add(tableInfo); + if (column.isEmpty()) + throw new SQLException("no parameter to execute"); + if (!isTableInfoEmpty()) + throw TSDBError.undeterminedExecutionError(); + bindAll(); return executeBatchImpl(); } @@ -709,18 +691,17 @@ public void addBatch() throws SQLException { throw new SQLException("column size not match, expected: " + fields.size() + ", actual: " + column.size()); } - private boolean isTableInfoBinded(){ - if (StringUtils.isEmpty(tableInfo.getTableName()) && tableInfo.getTagInfo().isEmpty() && tableInfo.getDataList().isEmpty()){ - return false; - } - return true; + private boolean isTableInfoEmpty(){ + return !StringUtils.isEmpty(tableInfo.getTableName()) + || !tableInfo.getTagInfo().isEmpty() + || !tableInfo.getDataList().isEmpty(); } @Override public int[] executeBatch() throws SQLException { if (column.isEmpty()) throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_BATCH_IS_EMPTY); - if (isTableInfoBinded()){ + if (isTableInfoEmpty()){ tableInfoList.add(tableInfo); } @@ -736,6 +717,10 @@ public void close() throws SQLException { super.close(); Request close = RequestFactory.generateClose(stmtId, reqId); transport.sendWithoutResponse(close); + Stmt2Resp resp = (Stmt2Resp) transport.send(close); + if (Code.SUCCESS.getCode() != resp.getCode()) { + throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); + } } @Override @@ -1056,9 +1041,6 @@ public void columnDataCloseBatch() throws SQLException { this.close(); } - - - @Override public void setTableName(String name) throws SQLException { this.tableInfo.setTableName(name); diff --git a/src/main/java/com/taosdata/jdbc/ws/WSStatement.java b/src/main/java/com/taosdata/jdbc/ws/WSStatement.java index 157187a3..cd7b3fcf 100644 --- a/src/main/java/com/taosdata/jdbc/ws/WSStatement.java +++ b/src/main/java/com/taosdata/jdbc/ws/WSStatement.java @@ -15,11 +15,11 @@ public class WSStatement extends AbstractStatement { protected Transport transport; - private String database; + protected String database; private final AbstractConnection connection; private boolean closed; - private ResultSet resultSet; + protected ResultSet resultSet; private int queryTimeout = 0; diff --git a/src/main/java/com/taosdata/jdbc/ws/entity/Action.java b/src/main/java/com/taosdata/jdbc/ws/entity/Action.java index 9c4e5793..acca3baa 100644 --- a/src/main/java/com/taosdata/jdbc/ws/entity/Action.java +++ b/src/main/java/com/taosdata/jdbc/ws/entity/Action.java @@ -1,8 +1,5 @@ package com.taosdata.jdbc.ws.entity; -import com.taosdata.jdbc.ws.stmt.entity.ExecResp; -import com.taosdata.jdbc.ws.stmt.entity.GetColFieldsResp; -import com.taosdata.jdbc.ws.stmt.entity.StmtResp; import com.taosdata.jdbc.ws.stmt2.entity.Stmt2ExecResp; import com.taosdata.jdbc.ws.stmt2.entity.Stmt2PrepareResp; import com.taosdata.jdbc.ws.stmt2.entity.Stmt2Resp; @@ -25,19 +22,6 @@ public enum Action { // free_result's class is meaningless FREE_RESULT("free_result", Response.class), - // stmt - INIT("init", StmtResp.class), - PREPARE("prepare", StmtResp.class), - SET_TABLE_NAME("set_table_name", StmtResp.class), - SET_TAGS("set_tags", StmtResp.class), - BIND("bind", StmtResp.class), - ADD_BATCH("add_batch", StmtResp.class), - EXEC("exec", ExecResp.class), - // response means nothing - GET_COL_FIELDS("get_col_fields", GetColFieldsResp.class), - - CLOSE("close", StmtResp.class), - // stmt2 STMT2_INIT("stmt2_init", Stmt2Resp.class), STMT2_PREPARE("stmt2_prepare", Stmt2PrepareResp.class), @@ -45,6 +29,7 @@ public enum Action { STMT2_EXEC("stmt2_exec", Stmt2ExecResp.class), // response means nothing STMT2_CLOSE("stmt2_close", Stmt2Resp.class), + STMT2_USE_RESULT("stmt2_result", Stmt2Resp.class), //schemaless INSERT("insert", CommonResp.class), diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/AddBatchReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/AddBatchReq.java deleted file mode 100644 index 3ac916a0..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/AddBatchReq.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.taosdata.jdbc.utils.UInt64Serializer; -import com.taosdata.jdbc.ws.entity.Payload; - -public class AddBatchReq extends Payload { - @JsonProperty("stmt_id") - @JsonSerialize(using = UInt64Serializer.class) - private long stmtId; - - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/BindReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/BindReq.java deleted file mode 100644 index 0140a318..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/BindReq.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.taosdata.jdbc.utils.UInt64Serializer; -import com.taosdata.jdbc.ws.entity.Payload; - -public class BindReq extends Payload { - @JsonProperty("stmt_id") - @JsonSerialize(using = UInt64Serializer.class) - private long stmtId; - private Object[] columns; - - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } - - public Object[] getColumns() { - return columns; - } - - public void setColumns(Object[] columns) { - this.columns = columns; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/CloseReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/CloseReq.java deleted file mode 100644 index 9f59912d..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/CloseReq.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.taosdata.jdbc.utils.UInt64Serializer; -import com.taosdata.jdbc.ws.entity.Payload; - -public class CloseReq extends Payload { - @JsonProperty("stmt_id") - @JsonSerialize(using = UInt64Serializer.class) - private long stmtId; - - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/ExecReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/ExecReq.java deleted file mode 100644 index f0d3d315..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/ExecReq.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.taosdata.jdbc.utils.UInt64Serializer; -import com.taosdata.jdbc.ws.entity.Payload; - -public class ExecReq extends Payload { - @JsonProperty("stmt_id") - @JsonSerialize(using = UInt64Serializer.class) - private long stmtId; - - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/ExecResp.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/ExecResp.java deleted file mode 100644 index cc388dcd..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/ExecResp.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.taosdata.jdbc.utils.UInt64Deserializer; -import com.taosdata.jdbc.ws.entity.CommonResp; - -public class ExecResp extends CommonResp { - @JsonProperty("stmt_id") - @JsonDeserialize(using = UInt64Deserializer.class) - private long stmtId; - private int affected; - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } - - public int getAffected() { - return affected; - } - - public void setAffected(int affected) { - this.affected = affected; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/Field.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/Field.java deleted file mode 100644 index 9dafe929..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/Field.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -public class Field { - private String name; - private byte field_type; - private byte precision; - private byte scale; - private int bytes; - - // getters and setters - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public byte getFieldType() { - return field_type; - } - - public void setFieldType(byte field_type) { - this.field_type = field_type; - } - - public byte getPrecision() { - return precision; - } - - public void setPrecision(byte precision) { - this.precision = precision; - } - - public byte getScale() { - return scale; - } - - public void setScale(byte scale) { - this.scale = scale; - } - - public int getBytes() { - return bytes; - } - - public void setBytes(int bytes) { - this.bytes = bytes; - } -} \ No newline at end of file diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/GetColFieldsReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/GetColFieldsReq.java deleted file mode 100644 index cf9d589f..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/GetColFieldsReq.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.taosdata.jdbc.utils.UInt64Serializer; -import com.taosdata.jdbc.ws.entity.Payload; - -public class GetColFieldsReq extends Payload { - @JsonProperty("stmt_id") - @JsonSerialize(using = UInt64Serializer.class) - - private long stmtId; - - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/GetColFieldsResp.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/GetColFieldsResp.java deleted file mode 100644 index 803d22ba..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/GetColFieldsResp.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.taosdata.jdbc.utils.UInt64Deserializer; -import com.taosdata.jdbc.ws.entity.CommonResp; - -import java.util.List; - -public class GetColFieldsResp extends CommonResp { - @JsonProperty("stmt_id") - @JsonDeserialize(using = UInt64Deserializer.class) - private long stmtId; - private List fields; - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } - - public List getFields() { - return fields; - } - - public void setFields(List fields) { - this.fields = fields; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/InitReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/InitReq.java deleted file mode 100644 index 2e5bba56..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/InitReq.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.taosdata.jdbc.ws.entity.Payload; - -public class InitReq extends Payload { -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/PrepareReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/PrepareReq.java deleted file mode 100644 index ebcc2d10..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/PrepareReq.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.taosdata.jdbc.utils.UInt64Serializer; -import com.taosdata.jdbc.ws.entity.Payload; - -public class PrepareReq extends Payload { - @JsonProperty("stmt_id") - @JsonSerialize(using = UInt64Serializer.class) - private long stmtId; - private String sql; - - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } - - public String getSql() { - return sql; - } - - public void setSql(String sql) { - this.sql = sql; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/RequestFactory.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/RequestFactory.java deleted file mode 100644 index 5ab3dd44..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/RequestFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - - -import com.taosdata.jdbc.ws.entity.Action; -import com.taosdata.jdbc.ws.entity.Request; - -/** - * generate id for request - */ -public class RequestFactory { - - private RequestFactory() { - } - - public static Request generateInit(long reqId) { - InitReq initReq = new InitReq(); - initReq.setReqId(reqId); - return new Request(Action.INIT.getAction(), initReq); - } - - public static Request generatePrepare(long stmtId, long reqId, String sql) { - PrepareReq prepareReq = new PrepareReq(); - prepareReq.setReqId(reqId); - prepareReq.setStmtId(stmtId); - prepareReq.setSql(sql); - return new Request(Action.PREPARE.getAction(), prepareReq); - } - - public static Request generateSetTableName(long stmtId, long reqId, String tableName) { - SetTableNameReq req = new SetTableNameReq(); - req.setReqId(reqId); - req.setStmtId(stmtId); - req.setName(tableName); - return new Request(Action.SET_TABLE_NAME.getAction(), req); - } - - public static Request generateSetTags(long stmtId, long reqId, Object[] tags) { - SetTagReq req = new SetTagReq(); - req.setReqId(reqId); - req.setStmtId(stmtId); - req.setTags(tags); - return new Request(Action.SET_TAGS.getAction(), req); - } - - public static Request generateBind(long stmtId, long reqId, Object[][] columns) { - BindReq req = new BindReq(); - req.setReqId(reqId); - req.setStmtId(stmtId); - req.setColumns(columns); - return new Request(Action.BIND.getAction(), req); - } - - public static Request generateBatch(long stmtId, long reqId) { - AddBatchReq req = new AddBatchReq(); - req.setReqId(reqId); - req.setStmtId(stmtId); - return new Request(Action.ADD_BATCH.getAction(), req); - } - - public static Request generateExec(long stmtId, long reqId) { - ExecReq req = new ExecReq(); - req.setReqId(reqId); - req.setStmtId(stmtId); - return new Request(Action.EXEC.getAction(), req); - } - public static Request generateGetColFields(long stmtId, long reqId) { - ExecReq req = new ExecReq(); - req.setReqId(reqId); - req.setStmtId(stmtId); - return new Request(Action.GET_COL_FIELDS.getAction(), req); - } - public static Request generateClose(long stmtId, long reqId) { - CloseReq req = new CloseReq(); - req.setReqId(reqId); - req.setStmtId(stmtId); - return new Request(Action.CLOSE.getAction(), req); - } - -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/SetTableNameReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/SetTableNameReq.java deleted file mode 100644 index bfdfd242..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/SetTableNameReq.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.taosdata.jdbc.utils.UInt64Serializer; -import com.taosdata.jdbc.ws.entity.Payload; - -public class SetTableNameReq extends Payload { - @JsonProperty("stmt_id") - @JsonSerialize(using = UInt64Serializer.class) - private long stmtId; - private String name; - - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/SetTagReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/SetTagReq.java deleted file mode 100644 index 7bcdbe55..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/SetTagReq.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.taosdata.jdbc.utils.UInt64Serializer; -import com.taosdata.jdbc.ws.entity.Payload; - -public class SetTagReq extends Payload { - @JsonProperty("stmt_id") - @JsonSerialize(using = UInt64Serializer.class) - private long stmtId; - private Object[] tags; - - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } - - public Object[] getTags() { - return tags; - } - - public void setTags(Object[] tags) { - this.tags = tags; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/StmtResp.java b/src/main/java/com/taosdata/jdbc/ws/stmt/entity/StmtResp.java deleted file mode 100644 index f1a27a59..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt/entity/StmtResp.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.taosdata.jdbc.ws.stmt.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.taosdata.jdbc.utils.UInt64Deserializer; -import com.taosdata.jdbc.ws.entity.CommonResp; - -// init | prepare | set_table_name | set_tags | bind | add_batch -public class StmtResp extends CommonResp { - @JsonProperty("stmt_id") - @JsonDeserialize(using = UInt64Deserializer.class) - private long stmtId; - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/BindReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/BindReq.java deleted file mode 100644 index 64e8d2a1..00000000 --- a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/BindReq.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.taosdata.jdbc.ws.stmt2.entity; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.taosdata.jdbc.utils.UInt64Serializer; -import com.taosdata.jdbc.ws.entity.Payload; - -public class BindReq extends Payload { - @JsonProperty("stmt_id") - @JsonSerialize(using = UInt64Serializer.class) - private long stmtId; - private Object[] columns; - - public long getStmtId() { - return stmtId; - } - - public void setStmtId(long stmtId) { - this.stmtId = stmtId; - } - - public Object[] getColumns() { - return columns; - } - - public void setColumns(Object[] columns) { - this.columns = columns; - } -} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/RequestFactory.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/RequestFactory.java index 9f2e7550..64dc6aef 100644 --- a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/RequestFactory.java +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/RequestFactory.java @@ -28,14 +28,6 @@ public static Request generatePrepare(long stmtId, long reqId, String sql) { return new Request(Action.STMT2_PREPARE.getAction(), prepareReq); } - public static Request generateBind(long stmtId, long reqId, Object[][] columns) { - BindReq req = new BindReq(); - req.setReqId(reqId); - req.setStmtId(stmtId); - req.setColumns(columns); - return new Request(Action.STMT2_BIND.getAction(), req); - } - public static Request generateExec(long stmtId, long reqId) { ExecReq req = new ExecReq(); req.setReqId(reqId); @@ -48,5 +40,10 @@ public static Request generateClose(long stmtId, long reqId) { req.setStmtId(stmtId); return new Request(Action.STMT2_CLOSE.getAction(), req); } - + public static Request generateUseResult(long stmtId, long reqId) { + ResultReq req = new ResultReq(); + req.setReqId(reqId); + req.setStmtId(stmtId); + return new Request(Action.STMT2_USE_RESULT.getAction(), req); + } } From d60993a5eec74f41e46d2ab3f82b2c660afbca37 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Thu, 12 Dec 2024 14:44:16 +0800 Subject: [PATCH 07/15] add stmt2 unit test, improve bind data perf --- pom.xml | 2 +- .../com/taosdata/jdbc/AbstractDriver.java | 2 +- .../taosdata/jdbc/common/DataLengthCfg.java | 33 +- .../taosdata/jdbc/common/SerializeBlock.java | 91 +++-- .../jdbc/ws/TSWSPreparedStatement.java | 298 ++++++++-------- .../com/taosdata/jdbc/ws/entity/Action.java | 3 +- .../jdbc/ws/stmt2/entity/ResultReq.java | 20 ++ .../jdbc/ws/stmt2/entity/ResultResp.java | 24 ++ .../jdbc/ws/WSPreparedStatementStmt2Test.java | 105 ------ .../WSPrepareStatementTest2.java} | 7 +- .../WSPreparedStatementAllTypeTest.java | 12 +- .../{ => stmt}/WSPreparedStatementNsTest.java | 2 +- .../ws/stmt/WSPreparedStatementStmt2Test.java | 329 ++++++++++++++++++ .../{ => stmt}/WSPreparedStatementTest.java | 3 +- 14 files changed, 604 insertions(+), 327 deletions(-) create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ResultReq.java create mode 100644 src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ResultResp.java delete mode 100644 src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementStmt2Test.java rename src/test/java/com/taosdata/jdbc/ws/{TaosPrepareStatementTest.java => stmt/WSPrepareStatementTest2.java} (97%) rename src/test/java/com/taosdata/jdbc/ws/{ => stmt}/WSPreparedStatementAllTypeTest.java (95%) rename src/test/java/com/taosdata/jdbc/ws/{ => stmt}/WSPreparedStatementNsTest.java (99%) create mode 100644 src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementStmt2Test.java rename src/test/java/com/taosdata/jdbc/ws/{ => stmt}/WSPreparedStatementTest.java (99%) diff --git a/pom.xml b/pom.xml index e0292459..5ccaf902 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.taosdata.jdbc taos-jdbcdriver - 3.4.1-SNAPSHOT + 3.5.0-SNAPSHOT jar JDBCDriver diff --git a/src/main/java/com/taosdata/jdbc/AbstractDriver.java b/src/main/java/com/taosdata/jdbc/AbstractDriver.java index 0799d1df..e392ea4b 100644 --- a/src/main/java/com/taosdata/jdbc/AbstractDriver.java +++ b/src/main/java/com/taosdata/jdbc/AbstractDriver.java @@ -74,7 +74,7 @@ protected Connection getWSConnection(String url, ConnectionParam param, Properti transport.setTextMessageHandler(message -> { try { - System.out.println("message = " + message); + log.trace("received message: {}", message); JsonNode jsonObject = JsonUtil.getObjectReader().readTree(message); Action action = Action.of(jsonObject.get("action").asText()); ObjectReader actionReader = JsonUtil.getObjectReader(action.getResponseClazz()); diff --git a/src/main/java/com/taosdata/jdbc/common/DataLengthCfg.java b/src/main/java/com/taosdata/jdbc/common/DataLengthCfg.java index e2f8fc7f..e0da523a 100644 --- a/src/main/java/com/taosdata/jdbc/common/DataLengthCfg.java +++ b/src/main/java/com/taosdata/jdbc/common/DataLengthCfg.java @@ -1,22 +1,23 @@ package com.taosdata.jdbc.common; -import java.util.HashMap; - -import static com.taosdata.jdbc.TSDBConstants.*; - public class DataLengthCfg { - private static final HashMap dataLengthMap= new HashMap(){{ - put(TSDB_DATA_TYPE_NULL, 1); - put(TSDB_DATA_TYPE_BOOL, 1); - put(TSDB_DATA_TYPE_TINYINT, 1); - put(TSDB_DATA_TYPE_SMALLINT, 2); - put(TSDB_DATA_TYPE_INT, 4); - put(TSDB_DATA_TYPE_BIGINT, 8); - put(TSDB_DATA_TYPE_FLOAT, 4); - put(TSDB_DATA_TYPE_DOUBLE, 8); - put(TSDB_DATA_TYPE_TIMESTAMP, 8); - }}; + private static final Integer[] dataLenArr = { + 1,//TSDB_DATA_TYPE_NULL + 1,//TSDB_DATA_TYPE_BOOL + 1,//TSDB_DATA_TYPE_TINYINT + 2,//TSDB_DATA_TYPE_SMALLINT + 4,//TSDB_DATA_TYPE_INT + 8,//TSDB_DATA_TYPE_BIGINT + 4,//TSDB_DATA_TYPE_FLOAT + 8,//TSDB_DATA_TYPE_DOUBLE + null, + 8//TSDB_DATA_TYPE_TIMESTAMP + }; + public static Integer getDataLength(int dataType){ - return dataLengthMap.get(dataType); + if (dataType < dataLenArr.length){ + return dataLenArr[dataType]; + } + return null; } } diff --git a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java index 9e94a376..d4cb484c 100644 --- a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java +++ b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java @@ -83,8 +83,8 @@ private static int serializeColumn(ColumnInfo columnInfo, byte[] buf, int offset offset += Integer.BYTES; // IsNull - for (int i = 0; i < columnInfo.getDataList().size(); i++) { - if (columnInfo.getDataList().get(i) == null) { + for (Object o: columnInfo.getDataList()) { + if (o == null) { buf[offset++] = 1; } else { buf[offset++] = 0; @@ -110,6 +110,7 @@ private static int serializeColumn(ColumnInfo columnInfo, byte[] buf, int offset } else { switch (columnInfo.getType()) { case TSDB_DATA_TYPE_BINARY: + case TSDB_DATA_TYPE_JSON: case TSDB_DATA_TYPE_VARBINARY: case TSDB_DATA_TYPE_GEOMETRY:{ byte[] v = (byte[]) o; @@ -118,7 +119,6 @@ private static int serializeColumn(ColumnInfo columnInfo, byte[] buf, int offset bufferLength += v.length; break; } - case TSDB_DATA_TYPE_JSON: case TSDB_DATA_TYPE_NCHAR: { String v = (String) o; int len = v.getBytes().length; @@ -250,17 +250,25 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse for (Object o: objectList){ if (o != null) { - Timestamp t = (Timestamp) o; - long v; - if (precision == TimestampPrecision.MS) { - v = t.getTime(); - } else if (precision == TimestampPrecision.US) { - v = t.getTime() * 1000L + t.getNanos() / 1000 % 1000; + if(o instanceof Timestamp) { + Timestamp t = (Timestamp) o; + long v; + if (precision == TimestampPrecision.MS) { + v = t.getTime(); + } else if (precision == TimestampPrecision.US) { + v = t.getTime() * 1000L + t.getNanos() / 1000 % 1000; + } else { + v = t.getTime() * 1000_000L + t.getNanos() % 1000_000L; + } + SerializeLong(buf, offset, v); + offset += Long.BYTES; + } else if (o instanceof Long){ + SerializeLong(buf, offset, (Long) o); + offset += Long.BYTES; } else { - v = t.getTime() * 1000_000L + t.getNanos() % 1000_000L; + throw new SQLException("unsupported timestamp data type : " + o.getClass().getName()); } - SerializeLong(buf, offset, v); - offset += Long.BYTES; + } else { SerializeLong(buf, offset, 0); offset += Long.BYTES; @@ -275,27 +283,26 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse private static void SerializeArrayDataType(int dataType , byte[] buf, int offset, List objectList) throws SQLException { switch (dataType) { + case TSDB_DATA_TYPE_JSON: case TSDB_DATA_TYPE_BINARY: case TSDB_DATA_TYPE_VARBINARY: case TSDB_DATA_TYPE_GEOMETRY:{ for (Object o: objectList){ if (o != null) { byte[] v = (byte[]) o; - for (byte b : v) { - buf[offset++] = b; - } + serializeByteArray(buf, offset, v); + offset += v.length; } } break; } - case TSDB_DATA_TYPE_JSON: case TSDB_DATA_TYPE_NCHAR: { for (Object o: objectList){ if (o != null) { String v = (String) o; - for (byte b : v.getBytes()) { - buf[offset++] = b; - } + byte[] bytes = v.getBytes(); + serializeByteArray(buf, offset, bytes); + offset += bytes.length; } } break; @@ -304,18 +311,6 @@ private static void SerializeArrayDataType(int dataType , byte[] buf, int offset throw new SQLException("unsupported data type : " + dataType); } } - public static int getTableNameTotalLength(List tableInfoList, int toBeBindTableNameIndex) throws SQLException{ - int totalLength = 0; - if (toBeBindTableNameIndex >= 0){ - for ( TableInfo tableInfo: tableInfoList){ - if (StringUtils.isEmpty(tableInfo.getTableName())) { - throw new SQLException("table name is empty"); - } - totalLength += tableInfo.getTableName().length() + 1; - } - } - return totalLength; - } public static int getTagTotalLengthByTableIndex(List tableInfoList, int index, int toBebindTagCount) throws SQLException{ int totalLength = 0; if (toBebindTagCount > 0){ @@ -324,7 +319,7 @@ public static int getTagTotalLengthByTableIndex(List tableInfoList, i } for (ColumnInfo tag : tableInfoList.get(index).getTagInfo()){ - if (tag.getDataList().get(index) == null){ + if (tag.getDataList().isEmpty()){ throw new SQLException("tag value is null, index: " + index); } int columnSize = getColumnSize(tag); @@ -360,6 +355,7 @@ public static int getColumnSize(ColumnInfo column) throws SQLException { } switch (column.getType()) { + case TSDB_DATA_TYPE_JSON: case TSDB_DATA_TYPE_BINARY: case TSDB_DATA_TYPE_VARBINARY: case TSDB_DATA_TYPE_GEOMETRY:{ @@ -373,7 +369,6 @@ public static int getColumnSize(ColumnInfo column) throws SQLException { // TotalLength(4) + Type (4) + Num(4) + IsNull(1) * size + haveLength(1) + BufferLength(4) + 4 * v.length + totalLength return 17 + (5 * column.getDataList().size()) + totalLength; } - case TSDB_DATA_TYPE_JSON: case TSDB_DATA_TYPE_NCHAR: { int totalLength = 0; for (Object o : column.getDataList()) { @@ -390,9 +385,6 @@ public static int getColumnSize(ColumnInfo column) throws SQLException { } } - - - public static byte[] getStmt2BindBlock(long reqId, long stmtId, List tableInfoList, @@ -405,8 +397,11 @@ public static byte[] getStmt2BindBlock(long reqId, int totalTableNameSize = 0; List tableNameSizeList = new ArrayList<>(); if (toBeBindTableNameIndex >= 0) { - for (int i = 0; i < tableInfoList.size(); i++) { - int tableNameSize = getTableNameTotalLength(tableInfoList, toBeBindTableNameIndex); + for (TableInfo tableInfo: tableInfoList) { + if (StringUtils.isEmpty(tableInfo.getTableName())){ + throw new SQLException("table name is empty"); + } + int tableNameSize = tableInfo.getTableName().length() + 1; totalTableNameSize += tableNameSize; tableNameSizeList.add((short) tableNameSize); } @@ -522,12 +517,12 @@ public static byte[] getStmt2BindBlock(long reqId, // TableNameLength if (toBebindTableNameCount > 0){ - for (Short tabeNameLen: tableNameSizeList){ - if (tabeNameLen == 0) { + for (Short tableNameLen: tableNameSizeList){ + if (tableNameLen == 0) { throw new SQLException("table name is empty"); } - SerializeShort(buf, offset, (short)(tabeNameLen + 1)); + SerializeShort(buf, offset, tableNameLen); offset += Short.BYTES; } @@ -551,7 +546,7 @@ public static byte[] getStmt2BindBlock(long reqId, for (int i = 0; i < tableInfoList.size(); i++) { for (ColumnInfo tag : tableInfoList.get(i).getTagInfo()){ - if (tag.getDataList().get(i) == null){ + if (tag.getDataList().isEmpty()){ throw new SQLException("tag value is null, index: " + i); } serializeColumn(tag, buf, offset, precision); @@ -576,12 +571,12 @@ public static byte[] getStmt2BindBlock(long reqId, } - for (int i = 30; i < buf.length; i++) { - int bb = buf[i] & 0xff; - System.out.print(bb); - System.out.print(","); - } - System.out.println(); +// for (int i = 30; i < buf.length; i++) { +// int bb = buf[i] & 0xff; +// System.out.print(bb); +// System.out.print(","); +// } +// System.out.println(); return buf; } diff --git a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java index 7812927c..d2fdcb9b 100644 --- a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java +++ b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java @@ -46,10 +46,10 @@ public class TSWSPreparedStatement extends WSStatement implements TaosPrepareSta private boolean isInsert = false; - private final Map column = new TreeMap<>(); + private final Map colOrderedMap = new TreeMap<>(); private final PriorityQueue tag = new PriorityQueue<>(); - private final PriorityQueue queue = new PriorityQueue<>(); + private final PriorityQueue colListQueue = new PriorityQueue<>(); private List tableInfoList = new ArrayList<>(); private TableInfo tableInfo; @@ -63,7 +63,7 @@ public TSWSPreparedStatement(Transport transport, ConnectionParam param, String return; reqId = ReqId.getReqID(); - Request request = RequestFactory.generateInit(reqId, true, false); + Request request = RequestFactory.generateInit(reqId, true, true); Stmt2Resp resp = (Stmt2Resp) transport.send(request); if (Code.SUCCESS.getCode() != resp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); @@ -121,19 +121,37 @@ public boolean execute(String sql, Long reqId) throws SQLException { return super.execute(sql, reqId); } + @Override + public boolean execute() throws SQLException { + if (isClosed()) + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); + + if (isInsert){ + executeUpdate(); + } else { + executeQuery(); + } + + return !isInsert; + } @Override public ResultSet executeQuery() throws SQLException { if (this.isInsert){ throw new SQLException("The query SQL must be prepared."); } - if (isTableInfoEmpty()){ + if (!tag.isEmpty() || !colListQueue.isEmpty()){ + throw new SQLException("The query SQL only support bind columns."); + } + + // only support jdbc standard bind api + if (colOrderedMap.isEmpty()){ return executeQuery(this.rawSql); } - if (!StringUtils.isEmpty(tableInfo.getTableName()) - || !tableInfo.getTagInfo().isEmpty()){ - throw new SQLException("only support bind columns."); + onlyBindCol(); + if (!isTableInfoEmpty()){ + tableInfoList.add(tableInfo); } this.executeBatchImpl(); @@ -151,24 +169,31 @@ public ResultSet executeQuery() throws SQLException { @Override public int executeUpdate() throws SQLException { + if (!this.isInsert){ + throw new SQLException("The insert SQL must be prepared."); + } if (fields.isEmpty()){ return this.executeUpdate(this.rawSql); } - if (column.isEmpty()) - throw new SQLException("no parameter to execute"); + if (colOrderedMap.size() == fields.size()){ + // bind all + bindAllColWithStdApi(); + } else{ + // mixed standard api and extended api, only support one table + onlyBindTag(); + onlyBindCol(); + } - if (!isTableInfoEmpty()) - throw TSDBError.undeterminedExecutionError(); + if (isTableInfoEmpty()){ + throw new SQLException("no data to be bind"); + } - bindAll(); + tableInfoList.add(tableInfo); return executeBatchImpl(); } - // set sub-table name - - public void setTagSqlTypeNull(int index, int type) throws SQLException { switch (type) { case Types.BOOLEAN: @@ -337,42 +362,42 @@ public void setTagJson(int index, String value) { public void setNull(int parameterIndex, int sqlType) throws SQLException { switch (sqlType) { case Types.BOOLEAN: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_BOOL, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_BOOL, parameterIndex)); break; case Types.TINYINT: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_TINYINT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_TINYINT, parameterIndex)); break; case Types.SMALLINT: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_SMALLINT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_SMALLINT, parameterIndex)); break; case Types.INTEGER: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_INT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_INT, parameterIndex)); break; case Types.BIGINT: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_BIGINT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_BIGINT, parameterIndex)); break; case Types.FLOAT: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_FLOAT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_FLOAT, parameterIndex)); break; case Types.DOUBLE: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_DOUBLE, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_DOUBLE, parameterIndex)); break; case Types.TIMESTAMP: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_TIMESTAMP, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_TIMESTAMP, parameterIndex)); break; case Types.BINARY: case Types.VARCHAR: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_BINARY, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_BINARY, parameterIndex)); break; case Types.VARBINARY: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_VARBINARY, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_VARBINARY, parameterIndex)); break; case Types.NCHAR: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_NCHAR, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_NCHAR, parameterIndex)); break; // json case Types.OTHER: - column.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_JSON, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(null, TSDB_DATA_TYPE_JSON, parameterIndex)); break; default: throw new SQLException("unsupported type: " + sqlType); @@ -381,37 +406,37 @@ public void setNull(int parameterIndex, int sqlType) throws SQLException { @Override public void setBoolean(int parameterIndex, boolean x) throws SQLException { - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BOOL, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BOOL, parameterIndex)); } @Override public void setByte(int parameterIndex, byte x) throws SQLException { - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_TINYINT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_TINYINT, parameterIndex)); } @Override public void setShort(int parameterIndex, short x) throws SQLException { - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_SMALLINT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_SMALLINT, parameterIndex)); } @Override public void setInt(int parameterIndex, int x) throws SQLException { - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_INT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_INT, parameterIndex)); } @Override public void setLong(int parameterIndex, long x) throws SQLException { - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BIGINT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BIGINT, parameterIndex)); } @Override public void setFloat(int parameterIndex, float x) throws SQLException { - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_FLOAT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_FLOAT, parameterIndex)); } @Override public void setDouble(int parameterIndex, double x) throws SQLException { - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_DOUBLE, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_DOUBLE, parameterIndex)); } @Override @@ -432,7 +457,7 @@ public void setString(int parameterIndex, String x) throws SQLException { @Override public void setBytes(int parameterIndex, byte[] x) throws SQLException { - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BINARY, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BINARY, parameterIndex)); } public void setVarbinary(int parameterIndex, byte[] x) throws SQLException { @@ -441,11 +466,11 @@ public void setVarbinary(int parameterIndex, byte[] x) throws SQLException { setNull(parameterIndex, Types.VARBINARY); return; } - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_VARBINARY, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_VARBINARY, parameterIndex)); } public void setGeometry(int parameterIndex, byte[] x) throws SQLException { - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_GEOMETRY, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_GEOMETRY, parameterIndex)); } @Override @@ -470,7 +495,7 @@ public void setTime(int parameterIndex, Time x) throws SQLException { @Override public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_TIMESTAMP, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_TIMESTAMP, parameterIndex)); } @Override @@ -490,9 +515,9 @@ public void setBinaryStream(int parameterIndex, InputStream x, int length) throw @Override public void clearParameters() throws SQLException { - column.clear(); + colOrderedMap.clear(); tag.clear(); - queue.clear(); + colListQueue.clear(); tableInfo = TableInfo.getEmptyTableInfo(); tableInfoList.clear(); @@ -502,42 +527,42 @@ public void clearParameters() throws SQLException { public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { switch (targetSqlType) { case Types.BOOLEAN: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BOOL, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BOOL, parameterIndex)); break; case Types.TINYINT: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_TINYINT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_TINYINT, parameterIndex)); break; case Types.SMALLINT: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_SMALLINT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_SMALLINT, parameterIndex)); break; case Types.INTEGER: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_INT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_INT, parameterIndex)); break; case Types.BIGINT: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BIGINT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BIGINT, parameterIndex)); break; case Types.FLOAT: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_FLOAT, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_FLOAT, parameterIndex)); break; case Types.DOUBLE: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_DOUBLE, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_DOUBLE, parameterIndex)); break; case Types.TIMESTAMP: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_TIMESTAMP, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_TIMESTAMP, parameterIndex)); break; case Types.BINARY: case Types.VARCHAR: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BINARY, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_BINARY, parameterIndex)); break; case Types.VARBINARY: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_VARBINARY, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_VARBINARY, parameterIndex)); break; case Types.NCHAR: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_NCHAR, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_NCHAR, parameterIndex)); break; // json case Types.OTHER: - column.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_JSON, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(x, TSDB_DATA_TYPE_JSON, parameterIndex)); break; default: throw new SQLException("unsupported type: " + targetSqlType); @@ -577,58 +602,49 @@ public void setObject(int parameterIndex, Object x) throws SQLException { } } - @Override - public boolean execute() throws SQLException { - if (isClosed()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED); - - List list = new ArrayList<>(); - while (!tag.isEmpty()){ - ColumnInfo columnInfo = tag.poll(); - if (columnInfo.getDataList().size() != 1){ - throw new SQLException("tag size is not equal 1"); - } - - list.add(columnInfo.getDataList().get(0)); - } - if (!column.isEmpty()) { - column.keySet().stream().sorted().forEach(i -> { - Column col = this.column.get(i); - list.add(col.data); - }); - } - Object[] parameters = list.toArray(new Object[0]); - this.clearParameters(); - final String sql = Utils.getNativeSql(this.rawSql, parameters); - return execute(sql); - } - private void bindAllToTableInfo(){ for (int index = 0; index < fields.size(); index++) { if (fields.get(index).getBindType() == FeildBindType.TAOS_FIELD_TBNAME.getValue()) { - tableInfo.setTableName(column.get(index + 1).data.toString()); + if (colOrderedMap.get(index + 1).data instanceof byte[]){ + tableInfo.setTableName(new String((byte[])colOrderedMap.get(index + 1).data, StandardCharsets.UTF_8)); + } + if (colOrderedMap.get(index + 1).data instanceof String){ + tableInfo.setTableName((String) colOrderedMap.get(index + 1).data); + } } else if (fields.get(index).getBindType() == FeildBindType.TAOS_FIELD_TAG.getValue()) { - tableInfo.getTagInfo().add(new ColumnInfo(index, Collections.singletonList(column.get(index + 1).data), fields.get(index).getFieldType())); + LinkedList list = new LinkedList<>(); + list.add(colOrderedMap.get(index + 1).data); + tableInfo.getTagInfo().add(new ColumnInfo(index + 1, list, fields.get(index).getFieldType())); } else if (fields.get(index).getBindType() == FeildBindType.TAOS_FIELD_COL.getValue()) { - tableInfo.getDataList().add(new ColumnInfo(index, Collections.singletonList(column.get(index + 1).data), fields.get(index).getFieldType())); + LinkedList list = new LinkedList<>(); + list.add(colOrderedMap.get(index + 1).data); + tableInfo.getDataList().add(new ColumnInfo(index + 1, list, fields.get(index).getFieldType())); } } } + private void bindColToTableInfo(){ - for (int index = 0; index < fields.size(); index++) { - if (fields.get(index).getBindType() == FeildBindType.TAOS_FIELD_COL.getValue()) { - tableInfo.getDataList().add(new ColumnInfo(index, Collections.singletonList(column.get(index + 1).data), fields.get(index).getFieldType())); - } + for (ColumnInfo columnInfo: tableInfo.getDataList()){ + columnInfo.add(colOrderedMap.get(columnInfo.getIndex()).data); } - } - private void bindAll(){ - if (toBeBindTableNameIndex >= 0){ - if (tableInfo.getTableName().isEmpty()) { - // first time, bind all - bindAllToTableInfo(); - } else { - if (tableInfo.getTableName().equals(column.get(toBeBindTableNameIndex + 1).toString())){ +// int j = 0; +// for (int index = 0; index < fields.size(); index++) { +// if (fields.get(index).getBindType() == FeildBindType.TAOS_FIELD_COL.getValue()) { +// tableInfo.getDataList().get(j).getDataList().add();add(new ColumnInfo(index, Collections.singletonList(colOrderedMap.get(index + 1).data), fields.get(index).getFieldType())); +// } +// } + } + + private void bindAllColWithStdApi() { + if (isTableInfoEmpty()) { + // first time, bind all + bindAllToTableInfo(); + } else { + if (toBeBindTableNameIndex >= 0) { + Object tbname = colOrderedMap.get(toBeBindTableNameIndex + 1).data; + if ((tbname instanceof String && tableInfo.getTableName().equals(tbname)) + || (tbname instanceof byte[] && tableInfo.getTableName().equals(new String((byte[]) tbname, StandardCharsets.UTF_8)))) { // same table, only bind col bindColToTableInfo(); } else { @@ -637,71 +653,61 @@ private void bindAll(){ tableInfo = TableInfo.getEmptyTableInfo(); bindAllToTableInfo(); } - } - } else { - // must same table - if (toBeBindTagCount > 0 && tableInfo.getTagInfo().isEmpty()){ - // first time, bind all - bindAllToTableInfo(); } else { - // only bind col + // must same table bindColToTableInfo(); } } } + private void onlyBindCol() { if (tableInfo.getDataList().isEmpty()){ - for (Map.Entry entry : column.entrySet()) { + for (Map.Entry entry : colOrderedMap.entrySet()) { Column col = entry.getValue(); List list = new ArrayList<>(); list.add(col.data); tableInfo.getDataList().add(new ColumnInfo(entry.getKey(), list, col.type)); } } else { - for (Map.Entry entry : column.entrySet()) { + for (Map.Entry entry : colOrderedMap.entrySet()) { Column col = entry.getValue(); tableInfo.getDataList().get(col.index - 1).add(col.data); } } } + private void onlyBindTag() { + if (!tableInfo.getTagInfo().isEmpty()){ + return; + } + + while (!tag.isEmpty()) { + tableInfo.getTagInfo().add(tag.poll()); + } + } @Override // Only support batch insert public void addBatch() throws SQLException { - if (column.size() == toBeBindColCount){ - if (toBeBindTableNameIndex < 0 && toBeBindTagCount == 0) { - onlyBindCol(); - } else { - if (toBeBindTableNameIndex >= 0 && tableInfo.getTableName().isEmpty()){ - throw new SQLException("table name is empty"); - } - if (tableInfo.getTagInfo().size()!= toBeBindTagCount){ - throw new SQLException("tag size not match, expected: " + toBeBindTagCount + ", actual: " + tableInfo.getTagInfo().size()); - } - onlyBindCol(); - } + if (colOrderedMap.size() == fields.size()){ + // jdbc standard bind api + bindAllColWithStdApi(); return; } - if (column.size() == fields.size()){ - // bind all - bindAll(); - return; - } - throw new SQLException("column size not match, expected: " + fields.size() + ", actual: " + column.size()); + // mixed standard api and extended api, only support one table + onlyBindTag(); + onlyBindCol(); } private boolean isTableInfoEmpty(){ - return !StringUtils.isEmpty(tableInfo.getTableName()) - || !tableInfo.getTagInfo().isEmpty() - || !tableInfo.getDataList().isEmpty(); + return StringUtils.isEmpty(tableInfo.getTableName()) + && tableInfo.getTagInfo().isEmpty() + && tableInfo.getDataList().isEmpty(); } @Override public int[] executeBatch() throws SQLException { - if (column.isEmpty()) - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_BATCH_IS_EMPTY); - if (isTableInfoEmpty()){ + if (!isTableInfoEmpty()){ tableInfoList.add(tableInfo); } @@ -743,9 +749,9 @@ public ParameterMetaData getParameterMetaData() throws SQLException { list.add(columnInfo.getDataList().get(0)); } - if (!column.isEmpty()) { - column.keySet().stream().sorted().forEach(i -> { - Column col = this.column.get(i); + if (!colOrderedMap.isEmpty()) { + colOrderedMap.keySet().stream().sorted().forEach(i -> { + Column col = this.colOrderedMap.get(i); list.add(col.data); }); } @@ -814,7 +820,7 @@ public void setRowId(int parameterIndex, RowId x) throws SQLException { @Override public void setNString(int parameterIndex, String value) throws SQLException { - column.put(parameterIndex, new Column(value, TSDB_DATA_TYPE_NCHAR, parameterIndex)); + colOrderedMap.put(parameterIndex, new Column(value, TSDB_DATA_TYPE_NCHAR, parameterIndex)); } @Override @@ -927,13 +933,7 @@ public void setFloat(int columnIndex, List list) throws SQLException { @Override public void setTimestamp(int columnIndex, List list) throws SQLException { - List collect = list.stream().map(x -> { - if (x == null) { - return null; - } - return new Timestamp(x); - }).collect(Collectors.toList()); - setValueImpl(columnIndex, collect, TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP, Long.BYTES); + setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP, Long.BYTES); } @Override @@ -985,20 +985,22 @@ public void setNString(int columnIndex, List list, int size) throws SQLE } public void setValueImpl(int columnIndex, List list, int type, int bytes) throws SQLException { - List listObject = list.stream() - .map(Object.class::cast) - .collect(Collectors.toList()); + List listObject = new ArrayList<>(list); ColumnInfo p = new ColumnInfo(columnIndex, listObject, type); - queue.add(p); + colListQueue.add(p); } @Override public void columnDataAddBatch() throws SQLException { + if (!colOrderedMap.isEmpty()){ + throw new SQLException("column data is not empty"); + } + while (!tag.isEmpty()){ tableInfo.getTagInfo().add(tag.poll()); } - while (!queue.isEmpty()) { - tableInfo.getDataList().add(queue.poll()); + while (!colListQueue.isEmpty()) { + tableInfo.getDataList().add(colListQueue.poll()); } tableInfoList.add(tableInfo); tableInfo = TableInfo.getEmptyTableInfo(); @@ -1015,22 +1017,26 @@ private int executeBatchImpl() throws SQLException { rawBlock = SerializeBlock.getStmt2BindBlock(reqId, stmtId, tableInfoList, toBeBindTableNameIndex, toBeBindTagCount, toBeBindColCount, precision); } catch (IOException e) { throw new SQLException("data serialize error!", e); + } finally { + this.clearParameters(); } + + // bind Stmt2Resp bindResp = (Stmt2Resp) transport.send(Action.STMT2_BIND.getAction(), reqId, rawBlock); if (Code.SUCCESS.getCode() != bindResp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(bindResp.getCode()) + "):" + bindResp.getMessage()); } - this.clearParameters(); - // send + // execute Request request = RequestFactory.generateExec(stmtId, reqId); Stmt2ExecResp resp = (Stmt2ExecResp) transport.send(request); if (Code.SUCCESS.getCode() != resp.getCode()) { throw new SQLException("(0x" + Integer.toHexString(resp.getCode()) + "):" + resp.getMessage()); } - return resp.getAffected(); + this.affectedRows = resp.getAffected(); + return this.affectedRows; } @Override public void columnDataExecuteBatch() throws SQLException { diff --git a/src/main/java/com/taosdata/jdbc/ws/entity/Action.java b/src/main/java/com/taosdata/jdbc/ws/entity/Action.java index acca3baa..72d96381 100644 --- a/src/main/java/com/taosdata/jdbc/ws/entity/Action.java +++ b/src/main/java/com/taosdata/jdbc/ws/entity/Action.java @@ -1,5 +1,6 @@ package com.taosdata.jdbc.ws.entity; +import com.taosdata.jdbc.ws.stmt2.entity.ResultResp; import com.taosdata.jdbc.ws.stmt2.entity.Stmt2ExecResp; import com.taosdata.jdbc.ws.stmt2.entity.Stmt2PrepareResp; import com.taosdata.jdbc.ws.stmt2.entity.Stmt2Resp; @@ -29,7 +30,7 @@ public enum Action { STMT2_EXEC("stmt2_exec", Stmt2ExecResp.class), // response means nothing STMT2_CLOSE("stmt2_close", Stmt2Resp.class), - STMT2_USE_RESULT("stmt2_result", Stmt2Resp.class), + STMT2_USE_RESULT("stmt2_result", ResultResp.class), //schemaless INSERT("insert", CommonResp.class), diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ResultReq.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ResultReq.java new file mode 100644 index 00000000..52512421 --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ResultReq.java @@ -0,0 +1,20 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.taosdata.jdbc.utils.UInt64Serializer; +import com.taosdata.jdbc.ws.entity.Payload; + +public class ResultReq extends Payload { + @JsonProperty("stmt_id") + @JsonSerialize(using = UInt64Serializer.class) + private long stmtId; + + public long getStmtId() { + return stmtId; + } + + public void setStmtId(long stmtId) { + this.stmtId = stmtId; + } +} diff --git a/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ResultResp.java b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ResultResp.java new file mode 100644 index 00000000..36d012fc --- /dev/null +++ b/src/main/java/com/taosdata/jdbc/ws/stmt2/entity/ResultResp.java @@ -0,0 +1,24 @@ +package com.taosdata.jdbc.ws.stmt2.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.taosdata.jdbc.utils.UInt64Deserializer; +import com.taosdata.jdbc.ws.entity.CommonResp; +import com.taosdata.jdbc.ws.entity.QueryResp; + +/** + * query result pojo + */ +public class ResultResp extends QueryResp { + @JsonProperty("stmt_id") + @JsonDeserialize(using = UInt64Deserializer.class) + private long stmtId; + + public long getStmtId() { + return stmtId; + } + + public void setStmtId(long stmtId) { + this.stmtId = stmtId; + } +} diff --git a/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementStmt2Test.java b/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementStmt2Test.java deleted file mode 100644 index 413619b2..00000000 --- a/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementStmt2Test.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.taosdata.jdbc.ws; - -import com.taosdata.jdbc.TSDBPreparedStatement; -import com.taosdata.jdbc.utils.SpecifyAddress; -import org.junit.*; - -import java.sql.*; -import java.util.*; -import java.util.Random; - -@FixMethodOrder -public class WSPreparedStatementStmt2Test { - String host = "127.0.0.1"; - String db_name = "ws_prepare"; - String tableName = "wpt"; - String superTable = "wpt_st"; - Connection connection; - - int numOfSubTable = 1; - int numOfRow = 10; - private static final Random random = new Random(System.currentTimeMillis()); - - @Test - public void testStmt2Insert() throws SQLException { - String sql = "INSERT INTO sub1 USING " + db_name + "." + tableName + " TAGS(?,?) VALUES (?,?,?,?)"; - - try (TSWSPreparedStatement pstmt = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class)) { - - for (int i = 1; i <= numOfSubTable; i++) { - // set table name - //pstmt.setTableName("d_bind_" + i); - - // set tags - pstmt.setTagInt(0, i); - pstmt.setTagString(1, "location_" + i); - - // set column ts - ArrayList tsList = new ArrayList<>(); - long current = System.currentTimeMillis(); - for (int j = 0; j < numOfRow; j++) - tsList.add(current + j); - pstmt.setTimestamp(0, tsList); - - // set column current - ArrayList currentList = new ArrayList<>(); - for (int j = 0; j < numOfRow; j++) - currentList.add(random.nextFloat() * 30); - pstmt.setFloat(1, currentList); - - // set column voltage - ArrayList voltageList = new ArrayList<>(); - for (int j = 0; j < numOfRow; j++) - voltageList.add(random.nextInt(300)); - pstmt.setInt(2, voltageList); - - // set column phase - ArrayList phaseList = new ArrayList<>(); - for (int j = 0; j < numOfRow; j++) - phaseList.add(random.nextFloat()); - pstmt.setFloat(3, phaseList); - // add column - pstmt.columnDataAddBatch(); - } - // execute column - pstmt.columnDataExecuteBatch(); - // you can check exeResult here - System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); - } catch (Exception ex) { - // please refer to the JDBC specifications for detailed exceptions info - System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", - ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", - ex.getMessage()); - // Print stack trace for context in examples. Use logging in production. - ex.printStackTrace(); - throw ex; - } - } - - - @Before - public void before() throws SQLException { - String url = SpecifyAddress.getInstance().getWebSocketWithoutUrl(); - if (url == null) { - url = "jdbc:TAOS-WS://" + host + ":6041/?user=root&password=taosdata"; - } else { - url += "?user=root&password=taosdata&batchfetch=true"; - } - Properties properties = new Properties(); - connection = DriverManager.getConnection(url, properties); - Statement statement = connection.createStatement(); - statement.execute("drop database if exists " + db_name); - statement.execute("create database " + db_name); - statement.execute("use " + db_name); - statement.execute("create stable if not exists " + db_name + "." + tableName + " (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - statement.close(); - } - - @After - public void after() throws SQLException { - try (Statement statement = connection.createStatement()) { - statement.execute("drop database if exists " + db_name); - } - connection.close(); - } -} diff --git a/src/test/java/com/taosdata/jdbc/ws/TaosPrepareStatementTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPrepareStatementTest2.java similarity index 97% rename from src/test/java/com/taosdata/jdbc/ws/TaosPrepareStatementTest.java rename to src/test/java/com/taosdata/jdbc/ws/stmt/WSPrepareStatementTest2.java index 2c5c2bf8..ebb79899 100644 --- a/src/test/java/com/taosdata/jdbc/ws/TaosPrepareStatementTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPrepareStatementTest2.java @@ -1,6 +1,7 @@ -package com.taosdata.jdbc.ws; +package com.taosdata.jdbc.ws.stmt; import com.taosdata.jdbc.utils.SpecifyAddress; +import com.taosdata.jdbc.ws.TSWSPreparedStatement; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -9,7 +10,7 @@ import java.sql.*; import java.util.Properties; -public class TaosPrepareStatementTest { +public class WSPrepareStatementTest2 { String host = "127.0.0.1"; String db_name = "ws_prepare_taos"; String superTable = "wpt_st"; @@ -90,7 +91,7 @@ public void testInsertSubTable() throws SQLException { " \"t10\": \"2021-01-01 00:00:00.000\",\n" + " \"t11\": \"taosdata\"\n" + " }"; // json string - statement.setTagJson(1, tagJson); + statement.setTagJson(0, tagJson); statement.setTimestamp(1, new Timestamp(System.currentTimeMillis())); statement.setInt(2, 100); statement.executeUpdate(); diff --git a/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementAllTypeTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeTest.java similarity index 95% rename from src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementAllTypeTest.java rename to src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeTest.java index 6b99bebe..7525d438 100644 --- a/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementAllTypeTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeTest.java @@ -1,12 +1,14 @@ -package com.taosdata.jdbc.ws; +package com.taosdata.jdbc.ws.stmt; import com.taosdata.jdbc.utils.SpecifyAddress; +import com.taosdata.jdbc.ws.TSWSPreparedStatement; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.sql.*; +import java.util.Collections; import java.util.Properties; public class WSPreparedStatementAllTypeTest { @@ -75,9 +77,11 @@ public void testExecuteUpdate2() throws SQLException { statement.setTagNString(9, "世界"); statement.setTagString(10, "hello world"); - statement.setTimestamp(1, new Timestamp(current)); - statement.setByte(2, (byte) 2); - statement.executeUpdate(); + + statement.setTimestamp(0, Collections.singletonList(current)); + statement.setByte(1, Collections.singletonList((byte) 2)); + statement.columnDataAddBatch(); + statement.columnDataExecuteBatch(); ResultSet resultSet = statement.executeQuery("select * from " + db_name + "." + stableName); resultSet.next(); diff --git a/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementNsTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementNsTest.java similarity index 99% rename from src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementNsTest.java rename to src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementNsTest.java index 1bb463a9..43133a02 100644 --- a/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementNsTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementNsTest.java @@ -1,4 +1,4 @@ -package com.taosdata.jdbc.ws; +package com.taosdata.jdbc.ws.stmt; import com.taosdata.jdbc.utils.SpecifyAddress; import org.junit.*; diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementStmt2Test.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementStmt2Test.java new file mode 100644 index 00000000..3ca999b0 --- /dev/null +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementStmt2Test.java @@ -0,0 +1,329 @@ +package com.taosdata.jdbc.ws.stmt; + +import com.taosdata.jdbc.TSDBPreparedStatement; +import com.taosdata.jdbc.utils.SpecifyAddress; +import com.taosdata.jdbc.ws.TSWSPreparedStatement; +import org.junit.*; + +import java.sql.*; +import java.util.*; +import java.util.Random; + +@FixMethodOrder +public class WSPreparedStatementStmt2Test { + String host = "127.0.0.1"; + String db_name = "ws_prepare"; + String tableName = "wpt"; + String superTable = "wpt_st"; + Connection connection; + + int numOfSubTable = 10; + int numOfRow = 10; + private static final Random random = new Random(System.currentTimeMillis()); + + @Test + public void testStmt2Insert() throws SQLException { + String sql = "INSERT INTO ? USING " + db_name + "." + tableName + " TAGS(?,?) VALUES (?,?,?,?)"; + + try (TSWSPreparedStatement pstmt = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class)) { + + for (int i = 1; i <= numOfSubTable; i++) { + //set table name + pstmt.setTableName("d_bind_" + i); + + // set tags + pstmt.setTagInt(0, i); + pstmt.setTagString(1, "location_" + i); + + // set column ts + ArrayList tsList = new ArrayList<>(); + long current = System.currentTimeMillis(); + for (int j = 0; j < numOfRow; j++) + tsList.add(current + j); + pstmt.setTimestamp(0, tsList); + + // set column current + ArrayList currentList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + currentList.add(random.nextFloat() * 30); + pstmt.setFloat(1, currentList); + + // set column voltage + ArrayList voltageList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + voltageList.add(random.nextInt(300)); + pstmt.setInt(2, voltageList); + + // set column phase + ArrayList phaseList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + phaseList.add(random.nextFloat()); + pstmt.setFloat(3, phaseList); + // add column + pstmt.columnDataAddBatch(); + } + // execute column + pstmt.columnDataExecuteBatch(); + // you can check exeResult here + System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); + } catch (Exception ex) { + // please refer to the JDBC specifications for detailed exceptions info + System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", + ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", + ex.getMessage()); + // Print stack trace for context in examples. Use logging in production. + ex.printStackTrace(); + throw ex; + } + } + + @Test + public void testStmt2InsertExtend() throws SQLException { + String sql = "INSERT INTO " + db_name + "." + tableName + " (tbname, ts, current, voltage, phase) VALUES (?,?,?,?,?)"; + + try (TSWSPreparedStatement pstmt = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class)) { + + for (int i = 1; i <= numOfSubTable; i++) { + //set table name + pstmt.setTableName("d_bind_" + i); + + // set column ts + ArrayList tsList = new ArrayList<>(); + long current = System.currentTimeMillis(); + for (int j = 0; j < numOfRow; j++) + tsList.add(current + j); + pstmt.setTimestamp(0, tsList); + + // set column current + ArrayList currentList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + currentList.add(random.nextFloat() * 30); + pstmt.setFloat(1, currentList); + + // set column voltage + ArrayList voltageList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + voltageList.add(random.nextInt(300)); + pstmt.setInt(2, voltageList); + + // set column phase + ArrayList phaseList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + phaseList.add(random.nextFloat()); + pstmt.setFloat(3, phaseList); + // add column + pstmt.columnDataAddBatch(); + } + // execute column + pstmt.columnDataExecuteBatch(); + // you can check exeResult here + System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); + } catch (Exception ex) { + // please refer to the JDBC specifications for detailed exceptions info + System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", + ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", + ex.getMessage()); + // Print stack trace for context in examples. Use logging in production. + ex.printStackTrace(); + throw ex; + } + } + + @Test + public void testStmt2InsertMixedApi() throws SQLException { + String sql = "INSERT INTO ? USING " + db_name + "." + tableName + " TAGS(?,?) VALUES (?,?,?,?)"; + + try (TSWSPreparedStatement pstmt = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class)) { + + for (int i = 1; i <= numOfSubTable; i++) { + //set table name + pstmt.setTableName("d_bind_" + i); + + // set tags + pstmt.setTagInt(0, i); + pstmt.setTagString(1, "location_" + i); + + // set columns + long current = System.currentTimeMillis(); + for (int j = 0; j < numOfRow; j++) { + pstmt.setTimestamp(1, new Timestamp(current + j)); + pstmt.setFloat(2, random.nextFloat() * 30); + pstmt.setInt(3, random.nextInt(300)); + pstmt.setFloat(4, random.nextFloat()); + pstmt.addBatch(); + } + int[] exeResult = pstmt.executeBatch(); + + for (int ele : exeResult){ + Assert.assertEquals(ele, Statement.SUCCESS_NO_INFO); + } + } + // you can check exeResult here + System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); + } catch (Exception ex) { + // please refer to the JDBC specifications for detailed exceptions info + System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", + ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", + ex.getMessage()); + // Print stack trace for context in examples. Use logging in production. + ex.printStackTrace(); + throw ex; + } + } + + @Test + public void testStmt2InsertSubTable() throws SQLException { + String sql = "INSERT INTO stb1 USING " + db_name + "." + tableName + " TAGS(?,?) VALUES (?,?,?,?)"; + + try (TSWSPreparedStatement pstmt = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class)) { + + for (int i = 1; i <= 1; i++) { + // set tags + pstmt.setTagInt(0, 1); + pstmt.setTagString(1, "location_" + 1); + + // set columns + long current = System.currentTimeMillis(); + for (int j = 0; j < numOfRow; j++) { + pstmt.setTimestamp(1, new Timestamp(current + j)); + pstmt.setFloat(2, random.nextFloat() * 30); + pstmt.setInt(3, random.nextInt(300)); + pstmt.setFloat(4, random.nextFloat()); + pstmt.addBatch(); + } + int[] exeResult = pstmt.executeBatch(); + + for (int ele : exeResult){ + Assert.assertEquals(ele, Statement.SUCCESS_NO_INFO); + } + } + // you can check exeResult here + System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); + } catch (Exception ex) { + // please refer to the JDBC specifications for detailed exceptions info + System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", + ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", + ex.getMessage()); + // Print stack trace for context in examples. Use logging in production. + ex.printStackTrace(); + throw ex; + } + } + + @Test + public void testStmt2InsertStdApi() throws SQLException { + String sql = "INSERT INTO " + db_name + "." + tableName + "(tbname, groupId, location, ts, current, voltage, phase) VALUES (?,?,?,?,?,?,?)"; + + try (TSWSPreparedStatement pstmt = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class)) { + + for (int i = 1; i <= numOfSubTable; i++) { + // set columns + long current = System.currentTimeMillis(); + for (int j = 0; j < numOfRow; j++) { + pstmt.setString(1, "d_bind_" + i); + pstmt.setInt(2, i); + pstmt.setString(3, "location_" + i); + + pstmt.setTimestamp(4, new Timestamp(current + j)); + pstmt.setFloat(5, random.nextFloat() * 30); + pstmt.setInt(6, random.nextInt(300)); + pstmt.setFloat(7, random.nextFloat()); + pstmt.addBatch(); + } + int[] exeResult = pstmt.executeBatch(); + + for (int ele : exeResult){ + Assert.assertEquals(ele, Statement.SUCCESS_NO_INFO); + } + } + // you can check exeResult here + System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); + } catch (Exception ex) { + // please refer to the JDBC specifications for detailed exceptions info + System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", + ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", + ex.getMessage()); + // Print stack trace for context in examples. Use logging in production. + ex.printStackTrace(); + throw ex; + } + } + + @Test + public void testStmt2InsertStdApiNoTag() throws SQLException { + // create sub table first + String createSql = "create table"; + for (int i = 1; i <= numOfSubTable; i++) { + createSql += " if not exists d_bind_" + i + " using " + db_name + "." + tableName + " tags(" + i + ", \"location_" + i + "\")"; + } + try (Statement stmt = connection.createStatement()) { + stmt.execute(createSql); + } catch (Exception ex) { + System.out.printf("Failed to create sub table, %sErrMessage: %s%n", + ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", + ex.getMessage()); + ex.printStackTrace(); + throw ex; + } + + String sql = "INSERT INTO " + db_name + "." + tableName + "(tbname, ts, current, voltage, phase) VALUES (?,?,?,?,?)"; + + try (TSWSPreparedStatement pstmt = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class)) { + + for (int i = 1; i <= numOfSubTable; i++) { + // set columns + long current = System.currentTimeMillis(); + for (int j = 0; j < numOfRow; j++) { + pstmt.setString(1, "d_bind_" + i); + + pstmt.setTimestamp(2, new Timestamp(current + j)); + pstmt.setFloat(3, random.nextFloat() * 30); + pstmt.setInt(4, random.nextInt(300)); + pstmt.setFloat(5, random.nextFloat()); + pstmt.addBatch(); + } + int[] exeResult = pstmt.executeBatch(); + + for (int ele : exeResult){ + Assert.assertEquals(ele, Statement.SUCCESS_NO_INFO); + } + } + // you can check exeResult here + System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); + } catch (Exception ex) { + // please refer to the JDBC specifications for detailed exceptions info + System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", + ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", + ex.getMessage()); + // Print stack trace for context in examples. Use logging in production. + ex.printStackTrace(); + throw ex; + } + } + + @Before + public void before() throws SQLException { + String url = SpecifyAddress.getInstance().getWebSocketWithoutUrl(); + if (url == null) { + url = "jdbc:TAOS-WS://" + host + ":6041/?user=root&password=taosdata"; + } else { + url += "?user=root&password=taosdata&batchfetch=true"; + } + Properties properties = new Properties(); + connection = DriverManager.getConnection(url, properties); + Statement statement = connection.createStatement(); + statement.execute("drop database if exists " + db_name); + statement.execute("create database " + db_name); + statement.execute("use " + db_name); + statement.execute("create stable if not exists " + db_name + "." + tableName + " (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); + statement.close(); + } + + @After + public void after() throws SQLException { + try (Statement statement = connection.createStatement()) { + statement.execute("drop database if exists " + db_name); + } + connection.close(); + } +} diff --git a/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementTest.java similarity index 99% rename from src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementTest.java rename to src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementTest.java index 29892678..34001b04 100644 --- a/src/test/java/com/taosdata/jdbc/ws/WSPreparedStatementTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementTest.java @@ -1,6 +1,7 @@ -package com.taosdata.jdbc.ws; +package com.taosdata.jdbc.ws.stmt; import com.taosdata.jdbc.utils.SpecifyAddress; +import com.taosdata.jdbc.ws.TSWSPreparedStatement; import org.junit.*; import java.io.InputStream; From f9a798db9d14f423e61fed6cf73b4edd008a7d47 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Thu, 12 Dec 2024 19:10:29 +0800 Subject: [PATCH 08/15] add bind null test case --- .../taosdata/jdbc/common/SerializeBlock.java | 19 +- .../WSPreparedStatementAllTypeNullTest.java | 174 ++++++++++++++++++ 2 files changed, 184 insertions(+), 9 deletions(-) create mode 100644 src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeNullTest.java diff --git a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java index d4cb484c..9b030b64 100644 --- a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java +++ b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java @@ -177,11 +177,12 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse offset += Integer.BYTES; for (Object o: objectList){ - short v = 0; if (o != null) { - v = (Short) o; + SerializeShort(buf, offset, (Short) o); + } else { + SerializeShort(buf, offset, (short)0); } - SerializeShort(buf, offset, v); + offset += Short.BYTES; } break; @@ -191,11 +192,11 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse offset += Integer.BYTES; for (Object o: objectList){ - int v = 0; if (o != null) { - v = (Integer) o; + SerializeInt(buf, offset, (Integer) o); + } else { + SerializeInt(buf, offset, 0); } - SerializeInt(buf, offset, v); offset += Integer.BYTES; } break; @@ -205,11 +206,11 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse offset += Integer.BYTES; for (Object o: objectList){ - long v = 0; if (o != null) { - v = (Long) o; + SerializeLong(buf, offset, (Long)o); + } else { + SerializeLong(buf, offset, 0L); } - SerializeLong(buf, offset, v); offset += Long.BYTES; } break; diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeNullTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeNullTest.java new file mode 100644 index 00000000..3f9b49ab --- /dev/null +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeNullTest.java @@ -0,0 +1,174 @@ +package com.taosdata.jdbc.ws.stmt; + +import com.taosdata.jdbc.utils.SpecifyAddress; +import com.taosdata.jdbc.ws.TSWSPreparedStatement; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.sql.*; +import java.util.Collections; +import java.util.Properties; + +import static com.taosdata.jdbc.TSDBConstants.*; + +public class WSPreparedStatementAllTypeNullTest { + String host = "127.0.0.1"; + String db_name = "ws_prepare_type"; + String tableName = "wpt"; + String stableName = "swpt"; + Connection connection; + + @Test + public void testExecuteUpdate() throws SQLException { + String sql = "insert into " + db_name + "." + tableName + " values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + PreparedStatement statement = connection.prepareStatement(sql); + long current = System.currentTimeMillis(); + statement.setTimestamp(1, new Timestamp(current)); + statement.setNull(2, Types.TINYINT); + statement.setNull(3, Types.SMALLINT); + statement.setNull(4, Types.INTEGER); + statement.setNull(5, Types.BIGINT); + statement.setNull(6, Types.FLOAT); + statement.setNull(7, Types.DOUBLE); + statement.setNull(8, Types.BOOLEAN); + + statement.setString(9, null); + statement.setNString(10, null); + statement.setString(11, null); + statement.executeUpdate(); + + ResultSet resultSet = statement.executeQuery("select * from " + db_name + "." + tableName); + resultSet.next(); + Assert.assertEquals(resultSet.getTimestamp(1), new Timestamp(current)); + + resultSet.getByte(2); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getShort(3); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getInt(4); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getLong(5); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getFloat(6); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getDouble(7); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getBoolean(8); + Assert.assertTrue(resultSet.wasNull()); + + Assert.assertNull(resultSet.getString(9)); + Assert.assertNull(resultSet.getString(10)); + Assert.assertNull(resultSet.getString(11)); + + resultSet.close(); + statement.close(); + } + + + @Test + public void testExecuteUpdate2() throws SQLException { + String sql = "insert into stb_1 using " + db_name + "." + stableName + " tags (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) values (?, ?)"; + TSWSPreparedStatement statement = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class); + long current = System.currentTimeMillis(); + + statement.setTagNull(0, TSDB_DATA_TYPE_TIMESTAMP); + statement.setTagNull(1, TSDB_DATA_TYPE_TINYINT); + statement.setTagNull(2, TSDB_DATA_TYPE_SMALLINT); + statement.setTagNull(3, TSDB_DATA_TYPE_INT); + statement.setTagNull(4, TSDB_DATA_TYPE_BIGINT); + statement.setTagNull(5, TSDB_DATA_TYPE_FLOAT); + statement.setTagNull(6, TSDB_DATA_TYPE_DOUBLE); + statement.setTagNull(7, TSDB_DATA_TYPE_BOOL); + + statement.setTagNull(8, TSDB_DATA_TYPE_BINARY); + statement.setTagNull(9, TSDB_DATA_TYPE_NCHAR); + statement.setTagNull(10, TSDB_DATA_TYPE_BINARY); + + statement.setTimestamp(0, Collections.singletonList(current)); + statement.setByte(1, Collections.singletonList(null)); + statement.columnDataAddBatch(); + statement.columnDataExecuteBatch(); + + ResultSet resultSet = statement.executeQuery("select * from " + db_name + "." + stableName); + resultSet.next(); + + + Assert.assertEquals(resultSet.getTimestamp(1), new Timestamp(current)); + + + resultSet.getByte(2); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getTimestamp(3); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getByte(4); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getShort(5); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getInt(6); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getLong(7); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getFloat(8); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getDouble(9); + Assert.assertTrue(resultSet.wasNull()); + + resultSet.getBoolean(10); + Assert.assertTrue(resultSet.wasNull()); + + Assert.assertNull(resultSet.getString(11)); + Assert.assertNull(resultSet.getString(12)); + Assert.assertNull(resultSet.getString(13)); + + resultSet.close(); + statement.close(); + } + + @Before + public void before() throws SQLException { + String url = SpecifyAddress.getInstance().getRestWithoutUrl(); + if (url == null) { + url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata&batchfetch=true"; + } else { + url += "?user=root&password=taosdata&batchfetch=true"; + } + Properties properties = new Properties(); + connection = DriverManager.getConnection(url, properties); + Statement statement = connection.createStatement(); + statement.execute("drop database if exists " + db_name); + statement.execute("create database " + db_name + " keep 36500"); + statement.execute("use " + db_name); + statement.execute("create table if not exists " + db_name + "." + tableName + + "(ts timestamp, c1 tinyint, c2 smallint, c3 int, c4 bigint, " + + "c5 float, c6 double, c7 bool, c8 binary(10), c9 nchar(10), c10 varchar(20))"); + + statement.execute("create stable if not exists " + db_name + "." + stableName + + "(ts timestamp, c1 tinyint) tags (t1 timestamp, t2 tinyint, t3 smallint, t4 int, t5 bigint, " + + "t6 float, t7 double, t8 bool, t9 binary(10), t10 nchar(10), t11 varchar(20))"); + + statement.close(); + } + + @After + public void after() throws SQLException { + try (Statement statement = connection.createStatement()){ + statement.execute("drop database if exists " + db_name); + } + connection.close(); + } +} From 9dcf3388d628fae7d98c2fbf4fdf2472fc1f025f Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Tue, 17 Dec 2024 15:37:08 +0800 Subject: [PATCH 09/15] rename test case --- ...ementAllTypeNullTest.java => WsPStmtAllTypeNullTest.java} | 2 +- ...aredStatementAllTypeTest.java => WsPstmtAllTypeTest.java} | 2 +- .../{WSPreparedStatementNsTest.java => WsPstmtNsTest.java} | 2 +- ...PreparedStatementStmt2Test.java => WsPstmtStmt2Test.java} | 5 ++--- ...WSPrepareStatementTest2.java => WsPstmtSubTableTest.java} | 2 +- .../stmt/{WSPreparedStatementTest.java => WsPstmtTest.java} | 4 +--- 6 files changed, 7 insertions(+), 10 deletions(-) rename src/test/java/com/taosdata/jdbc/ws/stmt/{WSPreparedStatementAllTypeNullTest.java => WsPStmtAllTypeNullTest.java} (99%) rename src/test/java/com/taosdata/jdbc/ws/stmt/{WSPreparedStatementAllTypeTest.java => WsPstmtAllTypeTest.java} (99%) rename src/test/java/com/taosdata/jdbc/ws/stmt/{WSPreparedStatementNsTest.java => WsPstmtNsTest.java} (99%) rename src/test/java/com/taosdata/jdbc/ws/stmt/{WSPreparedStatementStmt2Test.java => WsPstmtStmt2Test.java} (99%) rename src/test/java/com/taosdata/jdbc/ws/stmt/{WSPrepareStatementTest2.java => WsPstmtSubTableTest.java} (99%) rename src/test/java/com/taosdata/jdbc/ws/stmt/{WSPreparedStatementTest.java => WsPstmtTest.java} (99%) diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeNullTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPStmtAllTypeNullTest.java similarity index 99% rename from src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeNullTest.java rename to src/test/java/com/taosdata/jdbc/ws/stmt/WsPStmtAllTypeNullTest.java index 3f9b49ab..cce5b5be 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeNullTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPStmtAllTypeNullTest.java @@ -13,7 +13,7 @@ import static com.taosdata.jdbc.TSDBConstants.*; -public class WSPreparedStatementAllTypeNullTest { +public class WsPStmtAllTypeNullTest { String host = "127.0.0.1"; String db_name = "ws_prepare_type"; String tableName = "wpt"; diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtAllTypeTest.java similarity index 99% rename from src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeTest.java rename to src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtAllTypeTest.java index 7525d438..c1040aa9 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementAllTypeTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtAllTypeTest.java @@ -11,7 +11,7 @@ import java.util.Collections; import java.util.Properties; -public class WSPreparedStatementAllTypeTest { +public class WsPstmtAllTypeTest { String host = "127.0.0.1"; String db_name = "ws_prepare_type"; String tableName = "wpt"; diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementNsTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtNsTest.java similarity index 99% rename from src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementNsTest.java rename to src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtNsTest.java index 43133a02..d14c1e3c 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementNsTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtNsTest.java @@ -12,7 +12,7 @@ import static com.taosdata.jdbc.TSDBConstants.TIMESTAMP_DATA_OUT_OF_RANGE; @FixMethodOrder -public class WSPreparedStatementNsTest { +public class WsPstmtNsTest { String host = "localhost"; String db_name = "ws_prepare_ns"; String tableName = "wpt"; diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementStmt2Test.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java similarity index 99% rename from src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementStmt2Test.java rename to src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java index 3ca999b0..51186558 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementStmt2Test.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java @@ -1,6 +1,5 @@ package com.taosdata.jdbc.ws.stmt; -import com.taosdata.jdbc.TSDBPreparedStatement; import com.taosdata.jdbc.utils.SpecifyAddress; import com.taosdata.jdbc.ws.TSWSPreparedStatement; import org.junit.*; @@ -10,7 +9,7 @@ import java.util.Random; @FixMethodOrder -public class WSPreparedStatementStmt2Test { +public class WsPstmtStmt2Test { String host = "127.0.0.1"; String db_name = "ws_prepare"; String tableName = "wpt"; @@ -177,7 +176,7 @@ public void testStmt2InsertSubTable() throws SQLException { try (TSWSPreparedStatement pstmt = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class)) { - for (int i = 1; i <= 1; i++) { + for (int i = 1; i <= 10; i++) { // set tags pstmt.setTagInt(0, 1); pstmt.setTagString(1, "location_" + 1); diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPrepareStatementTest2.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtSubTableTest.java similarity index 99% rename from src/test/java/com/taosdata/jdbc/ws/stmt/WSPrepareStatementTest2.java rename to src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtSubTableTest.java index ebb79899..081242ee 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPrepareStatementTest2.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtSubTableTest.java @@ -10,7 +10,7 @@ import java.sql.*; import java.util.Properties; -public class WSPrepareStatementTest2 { +public class WsPstmtSubTableTest { String host = "127.0.0.1"; String db_name = "ws_prepare_taos"; String superTable = "wpt_st"; diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtTest.java similarity index 99% rename from src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementTest.java rename to src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtTest.java index 34001b04..7fdc7360 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WSPreparedStatementTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtTest.java @@ -14,10 +14,8 @@ import java.util.HashSet; import java.util.Properties; -import static com.taosdata.jdbc.TSDBConstants.*; - @FixMethodOrder -public class WSPreparedStatementTest { +public class WsPstmtTest { String host = "127.0.0.1"; String db_name = "ws_prepare"; String tableName = "wpt"; From 64e737df12d279f2f44d42903b0a7837dad62137 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Mon, 23 Dec 2024 14:37:46 +0800 Subject: [PATCH 10/15] update stmt2 test --- src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java index 51186558..5bc65ce3 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java @@ -213,7 +213,7 @@ public void testStmt2InsertSubTable() throws SQLException { public void testStmt2InsertStdApi() throws SQLException { String sql = "INSERT INTO " + db_name + "." + tableName + "(tbname, groupId, location, ts, current, voltage, phase) VALUES (?,?,?,?,?,?,?)"; - try (TSWSPreparedStatement pstmt = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class)) { + try (PreparedStatement pstmt = connection.prepareStatement(sql)) { for (int i = 1; i <= numOfSubTable; i++) { // set columns From 4cc1a8a563f24fe9d5be62a7c9c4ed7e8f8be4a9 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Mon, 23 Dec 2024 15:38:36 +0800 Subject: [PATCH 11/15] add stmt2 varbinary and geometry tests --- .../jdbc/ws/stmt/WsPStmtAllTypeNullTest.java | 17 +++++++++--- .../jdbc/ws/stmt/WsPstmtAllTypeTest.java | 27 +++++++++++++++---- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WsPStmtAllTypeNullTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPStmtAllTypeNullTest.java index cce5b5be..6628e8fc 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WsPStmtAllTypeNullTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPStmtAllTypeNullTest.java @@ -22,7 +22,7 @@ public class WsPStmtAllTypeNullTest { @Test public void testExecuteUpdate() throws SQLException { - String sql = "insert into " + db_name + "." + tableName + " values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + String sql = "insert into " + db_name + "." + tableName + " values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; PreparedStatement statement = connection.prepareStatement(sql); long current = System.currentTimeMillis(); statement.setTimestamp(1, new Timestamp(current)); @@ -37,6 +37,8 @@ public void testExecuteUpdate() throws SQLException { statement.setString(9, null); statement.setNString(10, null); statement.setString(11, null); + statement.setNull(12, Types.VARBINARY); + statement.setNull(13, Types.VARBINARY); statement.executeUpdate(); ResultSet resultSet = statement.executeQuery("select * from " + db_name + "." + tableName); @@ -68,6 +70,8 @@ public void testExecuteUpdate() throws SQLException { Assert.assertNull(resultSet.getString(10)); Assert.assertNull(resultSet.getString(11)); + Assert.assertNull(resultSet.getBytes(12)); + Assert.assertNull(resultSet.getBytes(13)); resultSet.close(); statement.close(); } @@ -75,7 +79,7 @@ public void testExecuteUpdate() throws SQLException { @Test public void testExecuteUpdate2() throws SQLException { - String sql = "insert into stb_1 using " + db_name + "." + stableName + " tags (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) values (?, ?)"; + String sql = "insert into stb_1 using " + db_name + "." + stableName + " tags (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) values (?, ?)"; TSWSPreparedStatement statement = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class); long current = System.currentTimeMillis(); @@ -92,6 +96,9 @@ public void testExecuteUpdate2() throws SQLException { statement.setTagNull(9, TSDB_DATA_TYPE_NCHAR); statement.setTagNull(10, TSDB_DATA_TYPE_BINARY); + statement.setTagNull(11, TSDB_DATA_TYPE_VARBINARY); + statement.setTagNull(12, TSDB_DATA_TYPE_GEOMETRY); + statement.setTimestamp(0, Collections.singletonList(current)); statement.setByte(1, Collections.singletonList(null)); statement.columnDataAddBatch(); @@ -135,6 +142,8 @@ public void testExecuteUpdate2() throws SQLException { Assert.assertNull(resultSet.getString(12)); Assert.assertNull(resultSet.getString(13)); + Assert.assertNull(resultSet.getBytes(14)); + Assert.assertNull(resultSet.getBytes(15)); resultSet.close(); statement.close(); } @@ -155,11 +164,11 @@ public void before() throws SQLException { statement.execute("use " + db_name); statement.execute("create table if not exists " + db_name + "." + tableName + "(ts timestamp, c1 tinyint, c2 smallint, c3 int, c4 bigint, " + - "c5 float, c6 double, c7 bool, c8 binary(10), c9 nchar(10), c10 varchar(20))"); + "c5 float, c6 double, c7 bool, c8 binary(10), c9 nchar(10), c10 varchar(20), c11 varbinary(100), c12 geometry(100))"); statement.execute("create stable if not exists " + db_name + "." + stableName + "(ts timestamp, c1 tinyint) tags (t1 timestamp, t2 tinyint, t3 smallint, t4 int, t5 bigint, " + - "t6 float, t7 double, t8 bool, t9 binary(10), t10 nchar(10), t11 varchar(20))"); + "t6 float, t7 double, t8 bool, t9 binary(10), t10 nchar(10), t11 varchar(20), t12 varbinary(100), t13 geometry(100))"); statement.close(); } diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtAllTypeTest.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtAllTypeTest.java index c1040aa9..f667dfc8 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtAllTypeTest.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtAllTypeTest.java @@ -1,6 +1,7 @@ package com.taosdata.jdbc.ws.stmt; import com.taosdata.jdbc.utils.SpecifyAddress; +import com.taosdata.jdbc.utils.StringUtils; import com.taosdata.jdbc.ws.TSWSPreparedStatement; import org.junit.After; import org.junit.Assert; @@ -17,10 +18,13 @@ public class WsPstmtAllTypeTest { String tableName = "wpt"; String stableName = "swpt"; Connection connection; + static String testStr = "20160601"; + static byte[] expectedVarBinary = StringUtils.hexToBytes(testStr); + static byte[] expectedGeometry = StringUtils.hexToBytes("0101000000000000000000F03F0000000000000040"); @Test public void testExecuteUpdate() throws SQLException { - String sql = "insert into " + db_name + "." + tableName + " values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + String sql = "insert into " + db_name + "." + tableName + " values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; PreparedStatement statement = connection.prepareStatement(sql); long current = System.currentTimeMillis(); statement.setTimestamp(1, new Timestamp(current)); @@ -34,6 +38,8 @@ public void testExecuteUpdate() throws SQLException { statement.setString(9, "你好"); statement.setNString(10, "世界"); statement.setString(11, "hello world"); + statement.setBytes(12, expectedVarBinary); + statement.setBytes(13, expectedGeometry); statement.executeUpdate(); ResultSet resultSet = statement.executeQuery("select * from " + db_name + "." + tableName); @@ -49,6 +55,8 @@ public void testExecuteUpdate() throws SQLException { Assert.assertEquals(resultSet.getString(9), "你好"); Assert.assertEquals(resultSet.getString(10), "世界"); Assert.assertEquals(resultSet.getString(11), "hello world"); + Assert.assertArrayEquals(resultSet.getBytes(12), expectedVarBinary); + Assert.assertArrayEquals(resultSet.getBytes(13), expectedGeometry); Assert.assertEquals(resultSet.getDate(1), new Date(current)); Assert.assertEquals(resultSet.getTime(1), new Time(current)); @@ -62,7 +70,7 @@ public void testExecuteUpdate() throws SQLException { @Test public void testExecuteUpdate2() throws SQLException { - String sql = "insert into stb_1 using " + db_name + "." + stableName + " tags (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) values (?, ?)"; + String sql = "insert into stb_1 using " + db_name + "." + stableName + " tags (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) values (?, ?)"; TSWSPreparedStatement statement = connection.prepareStatement(sql).unwrap(TSWSPreparedStatement.class); long current = System.currentTimeMillis(); statement.setTagTimestamp(0, new Timestamp(current)); @@ -76,6 +84,8 @@ public void testExecuteUpdate2() throws SQLException { statement.setTagString(8, "你好"); statement.setTagNString(9, "世界"); statement.setTagString(10, "hello world"); + statement.setTagVarbinary(11, expectedVarBinary); + statement.setTagGeometry(12, expectedGeometry); statement.setTimestamp(0, Collections.singletonList(current)); @@ -100,13 +110,17 @@ public void testExecuteUpdate2() throws SQLException { Assert.assertEquals(resultSet.getString(12), "世界"); Assert.assertEquals(resultSet.getString(13), "hello world"); + Assert.assertArrayEquals(resultSet.getBytes(14), expectedVarBinary); + Assert.assertArrayEquals(resultSet.getBytes(15), expectedGeometry); + + resultSet.close(); statement.close(); } @Test public void testExecuteCriticalValue() throws SQLException { - String sql = "insert into " + db_name + "." + tableName + " values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + String sql = "insert into " + db_name + "." + tableName + " values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; PreparedStatement statement = connection.prepareStatement(sql); statement.setTimestamp(1, new Timestamp(0)); statement.setByte(2, (byte) 127); @@ -119,6 +133,9 @@ public void testExecuteCriticalValue() throws SQLException { statement.setString(9, "ABC"); statement.setNString(10, "涛思数据"); statement.setString(11, "陶"); + statement.setBytes(12, expectedVarBinary); + statement.setBytes(13, expectedGeometry); + statement.executeUpdate(); statement.close(); } @@ -139,11 +156,11 @@ public void before() throws SQLException { statement.execute("use " + db_name); statement.execute("create table if not exists " + db_name + "." + tableName + "(ts timestamp, c1 tinyint, c2 smallint, c3 int, c4 bigint, " + - "c5 float, c6 double, c7 bool, c8 binary(10), c9 nchar(10), c10 varchar(20))"); + "c5 float, c6 double, c7 bool, c8 binary(10), c9 nchar(10), c10 varchar(20), c11 varbinary(100), c12 geometry(100))"); statement.execute("create stable if not exists " + db_name + "." + stableName + "(ts timestamp, c1 tinyint) tags (t1 timestamp, t2 tinyint, t3 smallint, t4 int, t5 bigint, " + - "t6 float, t7 double, t8 bool, t9 binary(10), t10 nchar(10), t11 varchar(20))"); + "t6 float, t7 double, t8 bool, t9 binary(10), t10 nchar(10), t11 varchar(20), t12 varbinary(100), t13 geometry(100))"); statement.close(); } From b933dedad75676468b9e91349e8b91014a6cd9d8 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Mon, 23 Dec 2024 17:29:42 +0800 Subject: [PATCH 12/15] improve exception --- .../taosdata/jdbc/common/SerializeBlock.java | 26 ++++++++++--------- .../jdbc/ws/TSWSPreparedStatement.java | 8 +++--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java index 9b030b64..5c56a32c 100644 --- a/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java +++ b/src/main/java/com/taosdata/jdbc/common/SerializeBlock.java @@ -1,5 +1,7 @@ package com.taosdata.jdbc.common; +import com.taosdata.jdbc.TSDBError; +import com.taosdata.jdbc.TSDBErrorNumbers; import com.taosdata.jdbc.enums.TimestampPrecision; import com.taosdata.jdbc.utils.StringUtils; @@ -128,7 +130,7 @@ private static int serializeColumn(ColumnInfo columnInfo, byte[] buf, int offset break; } default: - throw new SQLException("unsupported data type : " + columnInfo.getType()); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "unsupported data type : " + columnInfo.getType()); } } } @@ -267,7 +269,7 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse SerializeLong(buf, offset, (Long) o); offset += Long.BYTES; } else { - throw new SQLException("unsupported timestamp data type : " + o.getClass().getName()); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "unsupported timestamp data type : " + o.getClass().getName()); } } else { @@ -278,7 +280,7 @@ private static void SerializeNormalDataType(int dataType , byte[] buf, int offse break; } default: - throw new SQLException("unsupported data type : " + dataType); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "unsupported data type : " + dataType); } } @@ -309,19 +311,19 @@ private static void SerializeArrayDataType(int dataType , byte[] buf, int offset break; } default: - throw new SQLException("unsupported data type : " + dataType); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "unsupported data type : " + dataType); } } public static int getTagTotalLengthByTableIndex(List tableInfoList, int index, int toBebindTagCount) throws SQLException{ int totalLength = 0; if (toBebindTagCount > 0){ if (tableInfoList.get(index).getTagInfo().size() != toBebindTagCount){ - throw new SQLException("table tag size is not match"); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "table tag size is not match"); } for (ColumnInfo tag : tableInfoList.get(index).getTagInfo()){ if (tag.getDataList().isEmpty()){ - throw new SQLException("tag value is null, index: " + index); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "tag value is null, index: " + index); } int columnSize = getColumnSize(tag); tag.setSerializeSize(columnSize); @@ -335,7 +337,7 @@ public static int getColTotalLengthByTableIndex(List tableInfoList, i int totalLength = 0; if (toBebindColCount > 0){ if (tableInfoList.get(index).getDataList().size() != toBebindColCount){ - throw new SQLException("table column size is not match"); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "table column size is not match"); } for (ColumnInfo columnInfo : tableInfoList.get(index).getDataList()){ @@ -382,7 +384,7 @@ public static int getColumnSize(ColumnInfo column) throws SQLException { return 17 + (5 * column.getDataList().size()) + totalLength; } default: - throw new SQLException("unsupported data type : " + column.getType()); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "unsupported data type : " + column.getType()); } } @@ -400,7 +402,7 @@ public static byte[] getStmt2BindBlock(long reqId, if (toBeBindTableNameIndex >= 0) { for (TableInfo tableInfo: tableInfoList) { if (StringUtils.isEmpty(tableInfo.getTableName())){ - throw new SQLException("table name is empty"); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "table name is empty"); } int tableNameSize = tableInfo.getTableName().length() + 1; totalTableNameSize += tableNameSize; @@ -520,7 +522,7 @@ public static byte[] getStmt2BindBlock(long reqId, if (toBebindTableNameCount > 0){ for (Short tableNameLen: tableNameSizeList){ if (tableNameLen == 0) { - throw new SQLException("table name is empty"); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "table name is empty"); } SerializeShort(buf, offset, tableNameLen); @@ -529,7 +531,7 @@ public static byte[] getStmt2BindBlock(long reqId, for (TableInfo tableInfo: tableInfoList){ if (StringUtils.isEmpty(tableInfo.getTableName())) { - throw new SQLException("table name is empty"); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "table name is empty"); } serializeByteArray(buf, offset, tableInfo.getTableName().getBytes()); @@ -548,7 +550,7 @@ public static byte[] getStmt2BindBlock(long reqId, for (int i = 0; i < tableInfoList.size(); i++) { for (ColumnInfo tag : tableInfoList.get(i).getTagInfo()){ if (tag.getDataList().isEmpty()){ - throw new SQLException("tag value is null, index: " + i); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "tag value is null, index: " + i); } serializeColumn(tag, buf, offset, precision); offset += tag.getSerializeSize(); diff --git a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java index d2fdcb9b..f4ed17fc 100644 --- a/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java +++ b/src/main/java/com/taosdata/jdbc/ws/TSWSPreparedStatement.java @@ -137,11 +137,11 @@ public boolean execute() throws SQLException { @Override public ResultSet executeQuery() throws SQLException { if (this.isInsert){ - throw new SQLException("The query SQL must be prepared."); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "The query SQL must be prepared."); } if (!tag.isEmpty() || !colListQueue.isEmpty()){ - throw new SQLException("The query SQL only support bind columns."); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "The query SQL only support bind columns."); } // only support jdbc standard bind api @@ -170,7 +170,7 @@ public ResultSet executeQuery() throws SQLException { @Override public int executeUpdate() throws SQLException { if (!this.isInsert){ - throw new SQLException("The insert SQL must be prepared."); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE, "The insert SQL must be prepared."); } if (fields.isEmpty()){ @@ -187,7 +187,7 @@ public int executeUpdate() throws SQLException { } if (isTableInfoEmpty()){ - throw new SQLException("no data to be bind"); + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEUPDATE, "no data to be bind"); } tableInfoList.add(tableInfo); From bb8d21bfff1d4c4e34ee6e2a436ccccd060ae108 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Mon, 23 Dec 2024 17:31:55 +0800 Subject: [PATCH 13/15] update version --- README-CN.md | 2 +- README.md | 2 +- deploy-pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README-CN.md b/README-CN.md index f0cf2860..b8eae118 100644 --- a/README-CN.md +++ b/README-CN.md @@ -76,7 +76,7 @@ Maven 项目中,在 pom.xml 中添加以下依赖: com.taosdata.jdbc taos-jdbcdriver - 3.3.0 + 3.5.0 ``` diff --git a/README.md b/README.md index aa92a84d..1b425708 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Add following dependency in the `pom.xml` file of your Maven project: com.taosdata.jdbc taos-jdbcdriver - 3.0.* + 3.5.0 ``` diff --git a/deploy-pom.xml b/deploy-pom.xml index 303d53f7..157206dd 100755 --- a/deploy-pom.xml +++ b/deploy-pom.xml @@ -5,7 +5,7 @@ com.taosdata.jdbc taos-jdbcdriver - 3.4.1 + 3.5.0 jar JDBCDriver diff --git a/pom.xml b/pom.xml index 5ccaf902..2300804b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.taosdata.jdbc taos-jdbcdriver - 3.5.0-SNAPSHOT + 3.5.0 jar JDBCDriver From d0da3a81d97611b81cade85b3b98ad1d130abaa5 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Mon, 23 Dec 2024 20:25:23 +0800 Subject: [PATCH 14/15] add stmt2 escape case --- .../jdbc/ws/stmt/WsPstmtStmt2Test.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java index 5bc65ce3..6475d06c 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java @@ -248,6 +248,44 @@ public void testStmt2InsertStdApi() throws SQLException { } } + @Test + public void testStmt2InsertStdApiWithEscapeChar() throws SQLException { + String sql = "INSERT INTO `" + db_name + "`.`" + tableName + "` (tbname, groupId, location, ts, current, voltage, phase) VALUES (?,?,?,?,?,?,?)"; + + try (PreparedStatement pstmt = connection.prepareStatement(sql)) { + + for (int i = 1; i <= numOfSubTable; i++) { + // set columns + long current = System.currentTimeMillis(); + for (int j = 0; j < numOfRow; j++) { + pstmt.setString(1, "d_bind_" + i); + pstmt.setInt(2, i); + pstmt.setString(3, "location_" + i); + + pstmt.setTimestamp(4, new Timestamp(current + j)); + pstmt.setFloat(5, random.nextFloat() * 30); + pstmt.setInt(6, random.nextInt(300)); + pstmt.setFloat(7, random.nextFloat()); + pstmt.addBatch(); + } + int[] exeResult = pstmt.executeBatch(); + + for (int ele : exeResult){ + Assert.assertEquals(ele, Statement.SUCCESS_NO_INFO); + } + } + // you can check exeResult here + System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); + } catch (Exception ex) { + // please refer to the JDBC specifications for detailed exceptions info + System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", + ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", + ex.getMessage()); + // Print stack trace for context in examples. Use logging in production. + ex.printStackTrace(); + throw ex; + } + } @Test public void testStmt2InsertStdApiNoTag() throws SQLException { // create sub table first From 919cdaaecb0551df7e5d795f70e673319508f9f5 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Wed, 25 Dec 2024 14:47:01 +0800 Subject: [PATCH 15/15] remove testStmt2InsertStdApiWithEscapeChar --- .../jdbc/ws/stmt/WsPstmtStmt2Test.java | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java index 6475d06c..ecbdea75 100644 --- a/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java +++ b/src/test/java/com/taosdata/jdbc/ws/stmt/WsPstmtStmt2Test.java @@ -248,44 +248,44 @@ public void testStmt2InsertStdApi() throws SQLException { } } - @Test - public void testStmt2InsertStdApiWithEscapeChar() throws SQLException { - String sql = "INSERT INTO `" + db_name + "`.`" + tableName + "` (tbname, groupId, location, ts, current, voltage, phase) VALUES (?,?,?,?,?,?,?)"; - - try (PreparedStatement pstmt = connection.prepareStatement(sql)) { - - for (int i = 1; i <= numOfSubTable; i++) { - // set columns - long current = System.currentTimeMillis(); - for (int j = 0; j < numOfRow; j++) { - pstmt.setString(1, "d_bind_" + i); - pstmt.setInt(2, i); - pstmt.setString(3, "location_" + i); - - pstmt.setTimestamp(4, new Timestamp(current + j)); - pstmt.setFloat(5, random.nextFloat() * 30); - pstmt.setInt(6, random.nextInt(300)); - pstmt.setFloat(7, random.nextFloat()); - pstmt.addBatch(); - } - int[] exeResult = pstmt.executeBatch(); - - for (int ele : exeResult){ - Assert.assertEquals(ele, Statement.SUCCESS_NO_INFO); - } - } - // you can check exeResult here - System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); - } catch (Exception ex) { - // please refer to the JDBC specifications for detailed exceptions info - System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", - ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", - ex.getMessage()); - // Print stack trace for context in examples. Use logging in production. - ex.printStackTrace(); - throw ex; - } - } +// @Test +// public void testStmt2InsertStdApiWithEscapeChar() throws SQLException { +// String sql = "INSERT INTO `" + db_name + "`.`" + tableName + "` (tbname, groupId, location, ts, current, voltage, phase) VALUES (?,?,?,?,?,?,?)"; +// +// try (PreparedStatement pstmt = connection.prepareStatement(sql)) { +// +// for (int i = 1; i <= numOfSubTable; i++) { +// // set columns +// long current = System.currentTimeMillis(); +// for (int j = 0; j < numOfRow; j++) { +// pstmt.setString(1, "d_bind_" + i); +// pstmt.setInt(2, i); +// pstmt.setString(3, "location_" + i); +// +// pstmt.setTimestamp(4, new Timestamp(current + j)); +// pstmt.setFloat(5, random.nextFloat() * 30); +// pstmt.setInt(6, random.nextInt(300)); +// pstmt.setFloat(7, random.nextFloat()); +// pstmt.addBatch(); +// } +// int[] exeResult = pstmt.executeBatch(); +// +// for (int ele : exeResult){ +// Assert.assertEquals(ele, Statement.SUCCESS_NO_INFO); +// } +// } +// // you can check exeResult here +// System.out.println("Successfully inserted " + (numOfSubTable * numOfRow) + " rows to power.meters."); +// } catch (Exception ex) { +// // please refer to the JDBC specifications for detailed exceptions info +// System.out.printf("Failed to insert to table meters using stmt, %sErrMessage: %s%n", +// ex instanceof SQLException ? "ErrCode: " + ((SQLException) ex).getErrorCode() + ", " : "", +// ex.getMessage()); +// // Print stack trace for context in examples. Use logging in production. +// ex.printStackTrace(); +// throw ex; +// } +// } @Test public void testStmt2InsertStdApiNoTag() throws SQLException { // create sub table first