commit
6a8105839e
|
@ -54,14 +54,14 @@ void tscAddIntoSqlList(SSqlObj *pSql) {
|
||||||
pSql->next = pObj->sqlList;
|
pSql->next = pObj->sqlList;
|
||||||
if (pObj->sqlList) pObj->sqlList->prev = pSql;
|
if (pObj->sqlList) pObj->sqlList->prev = pSql;
|
||||||
pObj->sqlList = pSql;
|
pObj->sqlList = pSql;
|
||||||
pSql->queryId = queryId++;
|
pSql->queryId = atomic_fetch_add_32(&queryId, 1);
|
||||||
|
|
||||||
pthread_mutex_unlock(&pObj->mutex);
|
pthread_mutex_unlock(&pObj->mutex);
|
||||||
|
|
||||||
pSql->stime = taosGetTimestampMs();
|
pSql->stime = taosGetTimestampMs();
|
||||||
pSql->listed = 1;
|
pSql->listed = 1;
|
||||||
|
|
||||||
tscDebug("0x%"PRIx64" added into sqlList", pSql->self);
|
tscDebug("0x%"PRIx64" added into sqlList, queryId:%u", pSql->self, pSql->queryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tscSaveSlowQueryFpCb(void *param, TAOS_RES *result, int code) {
|
void tscSaveSlowQueryFpCb(void *param, TAOS_RES *result, int code) {
|
||||||
|
|
|
@ -2859,16 +2859,21 @@ void tscDoQuery(SSqlObj* pSql) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pCmd->command == TSDB_SQL_SELECT) {
|
|
||||||
tscAddIntoSqlList(pSql);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pCmd->dataSourceType == DATA_FROM_DATA_FILE) {
|
if (pCmd->dataSourceType == DATA_FROM_DATA_FILE) {
|
||||||
tscImportDataFromFile(pSql);
|
tscImportDataFromFile(pSql);
|
||||||
} else {
|
} else {
|
||||||
SQueryInfo *pQueryInfo = tscGetQueryInfo(pCmd, pCmd->clauseIndex);
|
SQueryInfo *pQueryInfo = tscGetQueryInfo(pCmd, pCmd->clauseIndex);
|
||||||
uint16_t type = pQueryInfo->type;
|
uint16_t type = pQueryInfo->type;
|
||||||
|
|
||||||
|
if ((pCmd->command == TSDB_SQL_SELECT) && (!TSDB_QUERY_HAS_TYPE(type, TSDB_QUERY_TYPE_SUBQUERY)) && (!TSDB_QUERY_HAS_TYPE(type, TSDB_QUERY_TYPE_STABLE_SUBQUERY))) {
|
||||||
|
tscAddIntoSqlList(pSql);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TSDB_QUERY_HAS_TYPE(type, TSDB_QUERY_TYPE_INSERT)) { // multi-vnodes insertion
|
||||||
|
tscHandleMultivnodeInsert(pSql);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (QUERY_IS_JOIN_QUERY(type)) {
|
if (QUERY_IS_JOIN_QUERY(type)) {
|
||||||
if (!TSDB_QUERY_HAS_TYPE(type, TSDB_QUERY_TYPE_SUBQUERY)) {
|
if (!TSDB_QUERY_HAS_TYPE(type, TSDB_QUERY_TYPE_SUBQUERY)) {
|
||||||
tscHandleMasterJoinQuery(pSql);
|
tscHandleMasterJoinQuery(pSql);
|
||||||
|
|
|
@ -98,7 +98,7 @@ TEST(testCase, parse_time) {
|
||||||
taosParseTime(t41, &time, strlen(t41), TSDB_TIME_PRECISION_MILLI, 0);
|
taosParseTime(t41, &time, strlen(t41), TSDB_TIME_PRECISION_MILLI, 0);
|
||||||
EXPECT_EQ(time, 852048000999);
|
EXPECT_EQ(time, 852048000999);
|
||||||
|
|
||||||
int64_t k = timezone;
|
// int64_t k = timezone;
|
||||||
char t42[] = "1997-1-1T0:0:0.999999999Z";
|
char t42[] = "1997-1-1T0:0:0.999999999Z";
|
||||||
taosParseTime(t42, &time, strlen(t42), TSDB_TIME_PRECISION_MILLI, 0);
|
taosParseTime(t42, &time, strlen(t42), TSDB_TIME_PRECISION_MILLI, 0);
|
||||||
EXPECT_EQ(time, 852048000999 - timezone * MILLISECOND_PER_SECOND);
|
EXPECT_EQ(time, 852048000999 - timezone * MILLISECOND_PER_SECOND);
|
||||||
|
@ -163,7 +163,7 @@ TEST(testCase, parse_time) {
|
||||||
taosParseTime(t13, &time, strlen(t13), TSDB_TIME_PRECISION_MILLI, 0);
|
taosParseTime(t13, &time, strlen(t13), TSDB_TIME_PRECISION_MILLI, 0);
|
||||||
EXPECT_EQ(time, -28800 * MILLISECOND_PER_SECOND);
|
EXPECT_EQ(time, -28800 * MILLISECOND_PER_SECOND);
|
||||||
|
|
||||||
char* t = "2021-01-08T02:11:40.000+00:00";
|
char t[] = "2021-01-08T02:11:40.000+00:00";
|
||||||
taosParseTime(t, &time, strlen(t), TSDB_TIME_PRECISION_MILLI, 0);
|
taosParseTime(t, &time, strlen(t), TSDB_TIME_PRECISION_MILLI, 0);
|
||||||
printf("%ld\n", time);
|
printf("%ld\n", time);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ public abstract class TSDBConstants {
|
||||||
public static final int JNI_FETCH_END = -6;
|
public static final int JNI_FETCH_END = -6;
|
||||||
public static final int JNI_OUT_OF_MEMORY = -7;
|
public static final int JNI_OUT_OF_MEMORY = -7;
|
||||||
// TSDB Data Types
|
// TSDB Data Types
|
||||||
|
public static final int TSDB_DATA_TYPE_NULL = 0;
|
||||||
public static final int TSDB_DATA_TYPE_BOOL = 1;
|
public static final int TSDB_DATA_TYPE_BOOL = 1;
|
||||||
public static final int TSDB_DATA_TYPE_TINYINT = 2;
|
public static final int TSDB_DATA_TYPE_TINYINT = 2;
|
||||||
public static final int TSDB_DATA_TYPE_SMALLINT = 3;
|
public static final int TSDB_DATA_TYPE_SMALLINT = 3;
|
||||||
|
|
|
@ -6,11 +6,13 @@ import com.google.common.primitives.Ints;
|
||||||
import com.google.common.primitives.Longs;
|
import com.google.common.primitives.Longs;
|
||||||
import com.google.common.primitives.Shorts;
|
import com.google.common.primitives.Shorts;
|
||||||
import com.taosdata.jdbc.*;
|
import com.taosdata.jdbc.*;
|
||||||
|
import com.taosdata.jdbc.utils.Utils;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
@ -18,14 +20,13 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
private volatile boolean isClosed;
|
private volatile boolean isClosed;
|
||||||
private int pos = -1;
|
private int pos = -1;
|
||||||
|
|
||||||
|
|
||||||
private final String database;
|
private final String database;
|
||||||
private final Statement statement;
|
private final Statement statement;
|
||||||
// data
|
// data
|
||||||
private final ArrayList<ArrayList<Object>> resultSet;
|
private final ArrayList<ArrayList<Object>> resultSet = new ArrayList<>();
|
||||||
// meta
|
// meta
|
||||||
private ArrayList<String> columnNames;
|
private ArrayList<String> columnNames = new ArrayList<>();
|
||||||
private ArrayList<Field> columns;
|
private ArrayList<Field> columns = new ArrayList<>();
|
||||||
private RestfulResultSetMetaData metaData;
|
private RestfulResultSetMetaData metaData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,10 +38,46 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
this.database = database;
|
this.database = database;
|
||||||
this.statement = statement;
|
this.statement = statement;
|
||||||
|
|
||||||
// column metadata
|
// get column metadata
|
||||||
JSONArray columnMeta = resultJson.getJSONArray("column_meta");
|
JSONArray columnMeta = resultJson.getJSONArray("column_meta");
|
||||||
columnNames = new ArrayList<>();
|
// get row data
|
||||||
columns = new ArrayList<>();
|
JSONArray data = resultJson.getJSONArray("data");
|
||||||
|
if (data == null || data.isEmpty()) {
|
||||||
|
columnNames.clear();
|
||||||
|
columns.clear();
|
||||||
|
this.resultSet.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// get head
|
||||||
|
JSONArray head = resultJson.getJSONArray("head");
|
||||||
|
// get rows
|
||||||
|
Integer rows = resultJson.getInteger("rows");
|
||||||
|
// parse column_meta
|
||||||
|
if (columnMeta != null) {
|
||||||
|
parseColumnMeta_new(columnMeta);
|
||||||
|
} else {
|
||||||
|
parseColumnMeta_old(head, data, rows);
|
||||||
|
}
|
||||||
|
this.metaData = new RestfulResultSetMetaData(this.database, columns, this);
|
||||||
|
// parse row data
|
||||||
|
resultSet.clear();
|
||||||
|
for (int rowIndex = 0; rowIndex < data.size(); rowIndex++) {
|
||||||
|
ArrayList row = new ArrayList();
|
||||||
|
JSONArray jsonRow = data.getJSONArray(rowIndex);
|
||||||
|
for (int colIndex = 0; colIndex < this.metaData.getColumnCount(); colIndex++) {
|
||||||
|
row.add(parseColumnData(jsonRow, colIndex, columns.get(colIndex).taos_type));
|
||||||
|
}
|
||||||
|
resultSet.add(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* use this method after TDengine-2.0.18.0 to parse column meta, restful add column_meta in resultSet
|
||||||
|
* @Param columnMeta
|
||||||
|
*/
|
||||||
|
private void parseColumnMeta_new(JSONArray columnMeta) throws SQLException {
|
||||||
|
columnNames.clear();
|
||||||
|
columns.clear();
|
||||||
for (int colIndex = 0; colIndex < columnMeta.size(); colIndex++) {
|
for (int colIndex = 0; colIndex < columnMeta.size(); colIndex++) {
|
||||||
JSONArray col = columnMeta.getJSONArray(colIndex);
|
JSONArray col = columnMeta.getJSONArray(colIndex);
|
||||||
String col_name = col.getString(0);
|
String col_name = col.getString(0);
|
||||||
|
@ -50,23 +87,55 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
columnNames.add(col_name);
|
columnNames.add(col_name);
|
||||||
columns.add(new Field(col_name, col_type, col_length, "", taos_type));
|
columns.add(new Field(col_name, col_type, col_length, "", taos_type));
|
||||||
}
|
}
|
||||||
this.metaData = new RestfulResultSetMetaData(this.database, columns, this);
|
}
|
||||||
|
|
||||||
// row data
|
/**
|
||||||
JSONArray data = resultJson.getJSONArray("data");
|
* use this method before TDengine-2.0.18.0 to parse column meta
|
||||||
resultSet = new ArrayList<>();
|
*/
|
||||||
for (int rowIndex = 0; rowIndex < data.size(); rowIndex++) {
|
private void parseColumnMeta_old(JSONArray head, JSONArray data, int rows) {
|
||||||
ArrayList row = new ArrayList();
|
columnNames.clear();
|
||||||
JSONArray jsonRow = data.getJSONArray(rowIndex);
|
columns.clear();
|
||||||
for (int colIndex = 0; colIndex < jsonRow.size(); colIndex++) {
|
for (int colIndex = 0; colIndex < head.size(); colIndex++) {
|
||||||
row.add(parseColumnData(jsonRow, colIndex, columns.get(colIndex).taos_type));
|
String col_name = head.getString(colIndex);
|
||||||
|
columnNames.add(col_name);
|
||||||
|
|
||||||
|
int col_type = Types.NULL;
|
||||||
|
int col_length = 0;
|
||||||
|
int taos_type = TSDBConstants.TSDB_DATA_TYPE_NULL;
|
||||||
|
|
||||||
|
JSONArray row0Json = data.getJSONArray(0);
|
||||||
|
if (colIndex < row0Json.size()) {
|
||||||
|
Object value = row0Json.get(colIndex);
|
||||||
|
if (value instanceof Boolean) {
|
||||||
|
col_type = Types.BOOLEAN;
|
||||||
|
col_length = 1;
|
||||||
|
taos_type = TSDBConstants.TSDB_DATA_TYPE_BOOL;
|
||||||
|
}
|
||||||
|
if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {
|
||||||
|
col_type = Types.BIGINT;
|
||||||
|
col_length = 8;
|
||||||
|
taos_type = TSDBConstants.TSDB_DATA_TYPE_BIGINT;
|
||||||
|
}
|
||||||
|
if (value instanceof Float || value instanceof Double || value instanceof BigDecimal) {
|
||||||
|
col_type = Types.DOUBLE;
|
||||||
|
col_length = 8;
|
||||||
|
taos_type = TSDBConstants.TSDB_DATA_TYPE_DOUBLE;
|
||||||
|
}
|
||||||
|
if (value instanceof String) {
|
||||||
|
col_type = Types.NCHAR;
|
||||||
|
col_length = ((String) value).length();
|
||||||
|
taos_type = TSDBConstants.TSDB_DATA_TYPE_NCHAR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
resultSet.add(row);
|
columns.add(new Field(col_name, col_type, col_length, "", taos_type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Object parseColumnData(JSONArray row, int colIndex, int taosType) throws SQLException {
|
private Object parseColumnData(JSONArray row, int colIndex, int taosType) throws SQLException {
|
||||||
switch (taosType) {
|
switch (taosType) {
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_NULL:
|
||||||
|
return null;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
||||||
return row.getBoolean(colIndex);
|
return row.getBoolean(colIndex);
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
||||||
|
@ -290,8 +359,10 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
wasNull = false;
|
wasNull = false;
|
||||||
if (value instanceof Float || value instanceof Double)
|
if (value instanceof Float)
|
||||||
return (float) value;
|
return (float) value;
|
||||||
|
if (value instanceof Double)
|
||||||
|
return new Float((Double) value);
|
||||||
return Float.parseFloat(value.toString());
|
return Float.parseFloat(value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,6 +400,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
return Shorts.toByteArray((short) value);
|
return Shorts.toByteArray((short) value);
|
||||||
if (value instanceof Byte)
|
if (value instanceof Byte)
|
||||||
return new byte[]{(byte) value};
|
return new byte[]{(byte) value};
|
||||||
|
if (value instanceof Timestamp) {
|
||||||
|
return Utils.formatTimestamp((Timestamp) value).getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
return value.toString().getBytes();
|
return value.toString().getBytes();
|
||||||
}
|
}
|
||||||
|
@ -342,7 +416,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
return null;
|
return null;
|
||||||
if (value instanceof Timestamp)
|
if (value instanceof Timestamp)
|
||||||
return new Date(((Timestamp) value).getTime());
|
return new Date(((Timestamp) value).getTime());
|
||||||
return Date.valueOf(value.toString());
|
Date date = null;
|
||||||
|
date = Utils.parseDate(value.toString());
|
||||||
|
return date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -354,7 +430,13 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
return null;
|
return null;
|
||||||
if (value instanceof Timestamp)
|
if (value instanceof Timestamp)
|
||||||
return new Time(((Timestamp) value).getTime());
|
return new Time(((Timestamp) value).getTime());
|
||||||
return Time.valueOf(value.toString());
|
Time time = null;
|
||||||
|
try {
|
||||||
|
time = Utils.parseTime(value.toString());
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
time = null;
|
||||||
|
}
|
||||||
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -366,14 +448,20 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
return null;
|
return null;
|
||||||
if (value instanceof Timestamp)
|
if (value instanceof Timestamp)
|
||||||
return (Timestamp) value;
|
return (Timestamp) value;
|
||||||
// if (value instanceof Long) {
|
if (value instanceof Long) {
|
||||||
// if (1_0000_0000_0000_0L > (long) value)
|
if (1_0000_0000_0000_0L > (long) value)
|
||||||
// return Timestamp.from(Instant.ofEpochMilli((long) value));
|
return Timestamp.from(Instant.ofEpochMilli((long) value));
|
||||||
// long epochSec = (long) value / 1000_000L;
|
long epochSec = (long) value / 1000_000L;
|
||||||
// long nanoAdjustment = (long) ((long) value % 1000_000L * 1000);
|
long nanoAdjustment = (long) value % 1000_000L * 1000;
|
||||||
// return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
|
return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
|
||||||
// }
|
}
|
||||||
return Timestamp.valueOf(value.toString());
|
Timestamp ret;
|
||||||
|
try {
|
||||||
|
ret = Utils.parseTimestamp(value.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
ret = null;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -415,7 +503,13 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
return new BigDecimal(Double.valueOf(value.toString()));
|
return new BigDecimal(Double.valueOf(value.toString()));
|
||||||
if (value instanceof Timestamp)
|
if (value instanceof Timestamp)
|
||||||
return new BigDecimal(((Timestamp) value).getTime());
|
return new BigDecimal(((Timestamp) value).getTime());
|
||||||
return new BigDecimal(value.toString());
|
BigDecimal ret;
|
||||||
|
try {
|
||||||
|
ret = new BigDecimal(value.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
ret = null;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
package com.taosdata.jdbc.utils;
|
|
||||||
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.time.format.DateTimeFormatterBuilder;
|
|
||||||
|
|
||||||
public class UtcTimestampUtil {
|
|
||||||
public static final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
|
|
||||||
.appendPattern("yyyy-MM-ddTHH:mm:ss.SSS+")
|
|
||||||
// .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
|
|
||||||
.toFormatter();
|
|
||||||
|
|
||||||
}
|
|
|
@ -5,7 +5,15 @@ import com.google.common.collect.RangeSet;
|
||||||
import com.google.common.collect.TreeRangeSet;
|
import com.google.common.collect.TreeRangeSet;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.sql.Date;
|
||||||
|
import java.sql.Time;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeFormatterBuilder;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -17,6 +25,41 @@ public class Utils {
|
||||||
|
|
||||||
private static Pattern ptn = Pattern.compile(".*?'");
|
private static Pattern ptn = Pattern.compile(".*?'");
|
||||||
|
|
||||||
|
private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
|
||||||
|
.appendPattern("yyyy-MM-dd HH:mm:ss.SSS").toFormatter();
|
||||||
|
private static final DateTimeFormatter formatter2 = new DateTimeFormatterBuilder()
|
||||||
|
.appendPattern("yyyy-MM-dd HH:mm:ss.SSSSSS").toFormatter();
|
||||||
|
|
||||||
|
public static Time parseTime(String timestampStr) throws DateTimeParseException {
|
||||||
|
LocalTime time;
|
||||||
|
try {
|
||||||
|
time = LocalTime.parse(timestampStr, formatter);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
time = LocalTime.parse(timestampStr, formatter2);
|
||||||
|
}
|
||||||
|
return Time.valueOf(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Date parseDate(String timestampStr) throws DateTimeParseException {
|
||||||
|
LocalDate date;
|
||||||
|
try {
|
||||||
|
date = LocalDate.parse(timestampStr, formatter);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
date = LocalDate.parse(timestampStr, formatter2);
|
||||||
|
}
|
||||||
|
return Date.valueOf(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Timestamp parseTimestamp(String timeStampStr) {
|
||||||
|
LocalDateTime dateTime;
|
||||||
|
try {
|
||||||
|
dateTime = LocalDateTime.parse(timeStampStr, formatter);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
dateTime = LocalDateTime.parse(timeStampStr, formatter2);
|
||||||
|
}
|
||||||
|
return Timestamp.valueOf(dateTime);
|
||||||
|
}
|
||||||
|
|
||||||
public static String escapeSingleQuota(String origin) {
|
public static String escapeSingleQuota(String origin) {
|
||||||
Matcher m = ptn.matcher(origin);
|
Matcher m = ptn.matcher(origin);
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
|
@ -133,4 +176,13 @@ public class Utils {
|
||||||
}).collect(Collectors.joining());
|
}).collect(Collectors.joining());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String formatTimestamp(Timestamp timestamp) {
|
||||||
|
int nanos = timestamp.getNanos();
|
||||||
|
if (nanos % 1000000l != 0)
|
||||||
|
return timestamp.toLocalDateTime().format(formatter2);
|
||||||
|
return timestamp.toLocalDateTime().format(formatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import java.sql.*;
|
||||||
public class InsertSpecialCharacterRestfulTest {
|
public class InsertSpecialCharacterRestfulTest {
|
||||||
|
|
||||||
private static final String host = "127.0.0.1";
|
private static final String host = "127.0.0.1";
|
||||||
// private static final String host = "master";
|
|
||||||
private static Connection conn;
|
private static Connection conn;
|
||||||
private static String dbName = "spec_char_test";
|
private static String dbName = "spec_char_test";
|
||||||
private static String tbname1 = "test";
|
private static String tbname1 = "test";
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
package com.taosdata.jdbc.cases;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.taosdata.jdbc.TSDBDriver;
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class TD4174Test {
|
||||||
|
private Connection conn;
|
||||||
|
private static final String host = "127.0.0.1";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
long ts = System.currentTimeMillis();
|
||||||
|
try (PreparedStatement pstmt = conn.prepareStatement("insert into weather values(" + ts + ", ?)")) {
|
||||||
|
JSONObject value = new JSONObject();
|
||||||
|
value.put("name", "John Smith");
|
||||||
|
value.put("age", 20);
|
||||||
|
Assert.assertEquals("{\"name\":\"John Smith\",\"age\":20}",value.toJSONString());
|
||||||
|
pstmt.setString(1, value.toJSONString());
|
||||||
|
|
||||||
|
int ret = pstmt.executeUpdate();
|
||||||
|
Assert.assertEquals(1, ret);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
JSONObject value = new JSONObject();
|
||||||
|
value.put("name", "John Smith");
|
||||||
|
value.put("age", 20);
|
||||||
|
System.out.println(value.toJSONString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() throws SQLException {
|
||||||
|
String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata";
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
||||||
|
|
||||||
|
conn = DriverManager.getConnection(url, properties);
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
stmt.execute("drop database if exists td4174");
|
||||||
|
stmt.execute("create database if not exists td4174");
|
||||||
|
stmt.execute("use td4174");
|
||||||
|
stmt.execute("create table weather(ts timestamp, text binary(64))");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() throws SQLException {
|
||||||
|
if (conn != null)
|
||||||
|
conn.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import java.util.Properties;
|
||||||
public class TwoTypeTimestampPercisionInRestfulTest {
|
public class TwoTypeTimestampPercisionInRestfulTest {
|
||||||
|
|
||||||
private static final String host = "127.0.0.1";
|
private static final String host = "127.0.0.1";
|
||||||
|
|
||||||
private static final String ms_timestamp_db = "ms_precision_test";
|
private static final String ms_timestamp_db = "ms_precision_test";
|
||||||
private static final String us_timestamp_db = "us_precision_test";
|
private static final String us_timestamp_db = "us_precision_test";
|
||||||
private static final long timestamp1 = System.currentTimeMillis();
|
private static final long timestamp1 = System.currentTimeMillis();
|
||||||
|
@ -94,7 +95,8 @@ public class TwoTypeTimestampPercisionInRestfulTest {
|
||||||
try (Statement stmt = conn3.createStatement()) {
|
try (Statement stmt = conn3.createStatement()) {
|
||||||
ResultSet rs = stmt.executeQuery("select last_row(ts) from " + ms_timestamp_db + ".weather");
|
ResultSet rs = stmt.executeQuery("select last_row(ts) from " + ms_timestamp_db + ".weather");
|
||||||
rs.next();
|
rs.next();
|
||||||
long ts = rs.getTimestamp(1).getTime();
|
Timestamp actual = rs.getTimestamp(1);
|
||||||
|
long ts = actual == null ? 0 : actual.getTime();
|
||||||
Assert.assertEquals(timestamp1, ts);
|
Assert.assertEquals(timestamp1, ts);
|
||||||
ts = rs.getLong(1);
|
ts = rs.getLong(1);
|
||||||
Assert.assertEquals(timestamp1, ts);
|
Assert.assertEquals(timestamp1, ts);
|
||||||
|
@ -110,7 +112,7 @@ public class TwoTypeTimestampPercisionInRestfulTest {
|
||||||
rs.next();
|
rs.next();
|
||||||
|
|
||||||
Timestamp timestamp = rs.getTimestamp(1);
|
Timestamp timestamp = rs.getTimestamp(1);
|
||||||
long ts = timestamp.getTime();
|
long ts = timestamp == null ? 0 : timestamp.getTime();
|
||||||
Assert.assertEquals(timestamp1, ts);
|
Assert.assertEquals(timestamp1, ts);
|
||||||
int nanos = timestamp.getNanos();
|
int nanos = timestamp.getNanos();
|
||||||
Assert.assertEquals(timestamp2 % 1000_000l * 1000, nanos);
|
Assert.assertEquals(timestamp2 % 1000_000l * 1000, nanos);
|
||||||
|
|
|
@ -9,19 +9,19 @@ import java.util.Properties;
|
||||||
|
|
||||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
public class UnsignedNumberJniTest {
|
public class UnsignedNumberJniTest {
|
||||||
|
|
||||||
private static final String host = "127.0.0.1";
|
private static final String host = "127.0.0.1";
|
||||||
private static Connection conn;
|
private static Connection conn;
|
||||||
|
private static long ts;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCase001() {
|
public void testCase001() {
|
||||||
try (Statement stmt = conn.createStatement()) {
|
try (Statement stmt = conn.createStatement()) {
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table");
|
ResultSet rs = stmt.executeQuery("select * from us_table");
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
assertResultSetMetaData(meta);
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
for (int i = 1; i <= meta.getColumnCount(); i++) {
|
Assert.assertEquals(ts, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(i) + ": " + rs.getString(i) + "\t");
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
Assert.assertEquals("127", rs.getString(2));
|
Assert.assertEquals("127", rs.getString(2));
|
||||||
Assert.assertEquals("32767", rs.getString(3));
|
Assert.assertEquals("32767", rs.getString(3));
|
||||||
Assert.assertEquals("2147483647", rs.getString(4));
|
Assert.assertEquals("2147483647", rs.getString(4));
|
||||||
|
@ -37,13 +37,10 @@ public class UnsignedNumberJniTest {
|
||||||
try (Statement stmt = conn.createStatement()) {
|
try (Statement stmt = conn.createStatement()) {
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table");
|
ResultSet rs = stmt.executeQuery("select * from us_table");
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
assertResultSetMetaData(meta);
|
||||||
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
Assert.assertEquals(ts, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
|
||||||
System.out.println();
|
|
||||||
Assert.assertEquals(127, rs.getByte(2));
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
Assert.assertEquals(32767, rs.getShort(3));
|
Assert.assertEquals(32767, rs.getShort(3));
|
||||||
Assert.assertEquals(2147483647, rs.getInt(4));
|
Assert.assertEquals(2147483647, rs.getInt(4));
|
||||||
|
@ -61,16 +58,14 @@ public class UnsignedNumberJniTest {
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,2147483647, 18446744073709551614)");
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,2147483647, 18446744073709551614)");
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
assertResultSetMetaData(meta);
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
Assert.assertEquals(now, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
|
||||||
System.out.println();
|
|
||||||
Assert.assertEquals(127, rs.getByte(2));
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
Assert.assertEquals(32767, rs.getShort(3));
|
Assert.assertEquals(32767, rs.getShort(3));
|
||||||
Assert.assertEquals(2147483647, rs.getInt(4));
|
Assert.assertEquals(2147483647, rs.getInt(4));
|
||||||
|
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
||||||
|
rs.getLong(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,15 +77,15 @@ public class UnsignedNumberJniTest {
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,4294967294, 18446744073709551614)");
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,4294967294, 18446744073709551614)");
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
assertResultSetMetaData(meta);
|
||||||
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
Assert.assertEquals(now, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
|
||||||
System.out.println();
|
|
||||||
Assert.assertEquals(127, rs.getByte(2));
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
Assert.assertEquals(32767, rs.getShort(3));
|
Assert.assertEquals(32767, rs.getShort(3));
|
||||||
|
Assert.assertEquals("4294967294", rs.getString(4));
|
||||||
|
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
||||||
|
rs.getInt(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,15 +97,15 @@ public class UnsignedNumberJniTest {
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 65534,4294967294, 18446744073709551614)");
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 65534,4294967294, 18446744073709551614)");
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
while (rs.next()) {
|
assertResultSetMetaData(meta);
|
||||||
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
|
||||||
System.out.println();
|
|
||||||
|
|
||||||
|
while (rs.next()) {
|
||||||
|
Assert.assertEquals(now, rs.getTimestamp(1).getTime());
|
||||||
Assert.assertEquals(127, rs.getByte(2));
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
|
Assert.assertEquals("65534", rs.getString(3));
|
||||||
|
Assert.assertEquals("4294967294", rs.getString(4));
|
||||||
|
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
||||||
|
rs.getShort(3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,37 +117,27 @@ public class UnsignedNumberJniTest {
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 254, 65534,4294967294, 18446744073709551614)");
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 254, 65534,4294967294, 18446744073709551614)");
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
while (rs.next()) {
|
assertResultSetMetaData(meta);
|
||||||
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
|
||||||
System.out.println();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCase007() throws SQLException {
|
|
||||||
try (Statement stmt = conn.createStatement()) {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 254, 65534,4294967294, 18446744073709551614)");
|
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
for (int i = 1; i <= meta.getColumnCount(); i++) {
|
Assert.assertEquals(now, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(i) + ": " + rs.getString(i) + "\t");
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
Assert.assertEquals("254", rs.getString(2));
|
Assert.assertEquals("254", rs.getString(2));
|
||||||
Assert.assertEquals("65534", rs.getString(3));
|
Assert.assertEquals("65534", rs.getString(3));
|
||||||
Assert.assertEquals("4294967294", rs.getString(4));
|
Assert.assertEquals("4294967294", rs.getString(4));
|
||||||
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
||||||
|
rs.getByte(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertResultSetMetaData(ResultSetMetaData meta) throws SQLException {
|
||||||
|
Assert.assertEquals(5, meta.getColumnCount());
|
||||||
|
Assert.assertEquals("ts", meta.getColumnLabel(1));
|
||||||
|
Assert.assertEquals("f1", meta.getColumnLabel(2));
|
||||||
|
Assert.assertEquals("f2", meta.getColumnLabel(3));
|
||||||
|
Assert.assertEquals("f3", meta.getColumnLabel(4));
|
||||||
|
Assert.assertEquals("f4", meta.getColumnLabel(5));
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void beforeClass() {
|
public static void beforeClass() {
|
||||||
|
@ -160,20 +145,19 @@ public class UnsignedNumberJniTest {
|
||||||
properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
||||||
properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
||||||
properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
||||||
|
ts = System.currentTimeMillis();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Class.forName("com.taosdata.jdbc.TSDBDriver");
|
|
||||||
final String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata";
|
final String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata";
|
||||||
conn = DriverManager.getConnection(url, properties);
|
conn = DriverManager.getConnection(url, properties);
|
||||||
|
|
||||||
Statement stmt = conn.createStatement();
|
Statement stmt = conn.createStatement();
|
||||||
stmt.execute("drop database if exists unsign_jni");
|
stmt.execute("drop database if exists unsign_jni");
|
||||||
stmt.execute("create database if not exists unsign_jni");
|
stmt.execute("create database if not exists unsign_jni");
|
||||||
stmt.execute("use unsign_jni");
|
stmt.execute("use unsign_jni");
|
||||||
stmt.execute("create table us_table(ts timestamp, f1 tinyint unsigned, f2 smallint unsigned, f3 int unsigned, f4 bigint unsigned)");
|
stmt.execute("create table us_table(ts timestamp, f1 tinyint unsigned, f2 smallint unsigned, f3 int unsigned, f4 bigint unsigned)");
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(now, 127, 32767,2147483647, 9223372036854775807)");
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + ts + ", 127, 32767,2147483647, 9223372036854775807)");
|
||||||
stmt.close();
|
stmt.close();
|
||||||
} catch (ClassNotFoundException | SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,17 +13,20 @@ public class UnsignedNumberRestfulTest {
|
||||||
|
|
||||||
private static final String host = "127.0.0.1";
|
private static final String host = "127.0.0.1";
|
||||||
private static Connection conn;
|
private static Connection conn;
|
||||||
|
private static long ts;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCase001() {
|
public void testCase001() {
|
||||||
try (Statement stmt = conn.createStatement()) {
|
try (Statement stmt = conn.createStatement()) {
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table");
|
ResultSet rs = stmt.executeQuery("select * from us_table");
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
assertResultSetMetaData(meta);
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
for (int i = 1; i <= meta.getColumnCount(); i++) {
|
Assert.assertEquals(ts, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(i) + ": " + rs.getString(i) + "\t");
|
Assert.assertEquals("127", rs.getString(2));
|
||||||
}
|
Assert.assertEquals("32767", rs.getString(3));
|
||||||
System.out.println();
|
Assert.assertEquals("2147483647", rs.getString(4));
|
||||||
|
Assert.assertEquals("9223372036854775807", rs.getString(5));
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -35,13 +38,14 @@ public class UnsignedNumberRestfulTest {
|
||||||
try (Statement stmt = conn.createStatement()) {
|
try (Statement stmt = conn.createStatement()) {
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table");
|
ResultSet rs = stmt.executeQuery("select * from us_table");
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
assertResultSetMetaData(meta);
|
||||||
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
Assert.assertEquals(ts, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
Assert.assertEquals(32767, rs.getShort(3));
|
||||||
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
Assert.assertEquals(2147483647, rs.getInt(4));
|
||||||
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
Assert.assertEquals(9223372036854775807l, rs.getLong(5));
|
||||||
System.out.println();
|
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -55,13 +59,14 @@ public class UnsignedNumberRestfulTest {
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,2147483647, 18446744073709551614)");
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,2147483647, 18446744073709551614)");
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
assertResultSetMetaData(meta);
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
Assert.assertEquals(now, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
Assert.assertEquals(32767, rs.getShort(3));
|
||||||
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
Assert.assertEquals(2147483647, rs.getInt(4));
|
||||||
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
||||||
System.out.println();
|
rs.getLong(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,13 +78,15 @@ public class UnsignedNumberRestfulTest {
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,4294967294, 18446744073709551614)");
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,4294967294, 18446744073709551614)");
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
assertResultSetMetaData(meta);
|
||||||
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
Assert.assertEquals(now, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
Assert.assertEquals(32767, rs.getShort(3));
|
||||||
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
Assert.assertEquals("4294967294", rs.getString(4));
|
||||||
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
||||||
System.out.println();
|
rs.getInt(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,13 +98,15 @@ public class UnsignedNumberRestfulTest {
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 65534,4294967294, 18446744073709551614)");
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 65534,4294967294, 18446744073709551614)");
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
assertResultSetMetaData(meta);
|
||||||
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
Assert.assertEquals(now, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
Assert.assertEquals("65534", rs.getString(3));
|
||||||
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
Assert.assertEquals("4294967294", rs.getString(4));
|
||||||
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
||||||
System.out.println();
|
rs.getShort(3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,57 +118,47 @@ public class UnsignedNumberRestfulTest {
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 254, 65534,4294967294, 18446744073709551614)");
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 254, 65534,4294967294, 18446744073709551614)");
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
while (rs.next()) {
|
assertResultSetMetaData(meta);
|
||||||
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
|
||||||
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
|
||||||
System.out.println();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCase007() throws SQLException {
|
|
||||||
try (Statement stmt = conn.createStatement()) {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 254, 65534,4294967294, 18446744073709551614)");
|
|
||||||
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
|
||||||
ResultSetMetaData meta = rs.getMetaData();
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
for (int i = 1; i <= meta.getColumnCount(); i++) {
|
Assert.assertEquals(now, rs.getTimestamp(1).getTime());
|
||||||
System.out.print(meta.getColumnLabel(i) + ": " + rs.getString(i) + "\t");
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
Assert.assertEquals("254", rs.getString(2));
|
Assert.assertEquals("254", rs.getString(2));
|
||||||
Assert.assertEquals("65534", rs.getString(3));
|
Assert.assertEquals("65534", rs.getString(3));
|
||||||
Assert.assertEquals("4294967294", rs.getString(4));
|
Assert.assertEquals("4294967294", rs.getString(4));
|
||||||
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
||||||
|
rs.getByte(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertResultSetMetaData(ResultSetMetaData meta) throws SQLException {
|
||||||
|
Assert.assertEquals(5, meta.getColumnCount());
|
||||||
|
Assert.assertEquals("ts", meta.getColumnLabel(1));
|
||||||
|
Assert.assertEquals("f1", meta.getColumnLabel(2));
|
||||||
|
Assert.assertEquals("f2", meta.getColumnLabel(3));
|
||||||
|
Assert.assertEquals("f3", meta.getColumnLabel(4));
|
||||||
|
Assert.assertEquals("f4", meta.getColumnLabel(5));
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void beforeClass() {
|
public static void beforeClass() {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
||||||
properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
||||||
properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
||||||
|
ts = System.currentTimeMillis();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Class.forName("com.taosdata.jdbc.rs.RestfulDriver");
|
|
||||||
final String url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata";
|
final String url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata";
|
||||||
conn = DriverManager.getConnection(url, properties);
|
conn = DriverManager.getConnection(url, properties);
|
||||||
|
|
||||||
Statement stmt = conn.createStatement();
|
Statement stmt = conn.createStatement();
|
||||||
stmt.execute("drop database if exists unsign_restful");
|
stmt.execute("drop database if exists unsign_restful");
|
||||||
stmt.execute("create database if not exists unsign_restful");
|
stmt.execute("create database if not exists unsign_restful");
|
||||||
stmt.execute("use unsign_restful");
|
stmt.execute("use unsign_restful");
|
||||||
stmt.execute("create table us_table(ts timestamp, f1 tinyint unsigned, f2 smallint unsigned, f3 int unsigned, f4 bigint unsigned)");
|
stmt.execute("create table us_table(ts timestamp, f1 tinyint unsigned, f2 smallint unsigned, f3 int unsigned, f4 bigint unsigned)");
|
||||||
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(now, 127, 32767,2147483647, 9223372036854775807)");
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + ts + ", 127, 32767,2147483647, 9223372036854775807)");
|
||||||
stmt.close();
|
stmt.close();
|
||||||
} catch (ClassNotFoundException | SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import java.sql.*;
|
||||||
|
|
||||||
public class RestfulPreparedStatementTest {
|
public class RestfulPreparedStatementTest {
|
||||||
private static final String host = "127.0.0.1";
|
private static final String host = "127.0.0.1";
|
||||||
// private static final String host = "master";
|
|
||||||
private static Connection conn;
|
private static Connection conn;
|
||||||
private static final String sql_insert = "insert into t1 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
private static final String sql_insert = "insert into t1 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
private static PreparedStatement pstmt_insert;
|
private static PreparedStatement pstmt_insert;
|
||||||
|
@ -371,7 +370,6 @@ public class RestfulPreparedStatementTest {
|
||||||
pstmt_insert.setSQLXML(1, null);
|
pstmt_insert.setSQLXML(1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void beforeClass() {
|
public static void beforeClass() {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -18,7 +18,6 @@ import java.text.SimpleDateFormat;
|
||||||
public class RestfulResultSetTest {
|
public class RestfulResultSetTest {
|
||||||
|
|
||||||
private static final String host = "127.0.0.1";
|
private static final String host = "127.0.0.1";
|
||||||
|
|
||||||
private static Connection conn;
|
private static Connection conn;
|
||||||
private static Statement stmt;
|
private static Statement stmt;
|
||||||
private static ResultSet rs;
|
private static ResultSet rs;
|
||||||
|
@ -95,7 +94,8 @@ public class RestfulResultSetTest {
|
||||||
@Test
|
@Test
|
||||||
public void getBigDecimal() throws SQLException {
|
public void getBigDecimal() throws SQLException {
|
||||||
BigDecimal f1 = rs.getBigDecimal("f1");
|
BigDecimal f1 = rs.getBigDecimal("f1");
|
||||||
Assert.assertEquals(1609430400000l, f1.longValue());
|
long actual = (f1 == null) ? 0 : f1.longValue();
|
||||||
|
Assert.assertEquals(1609430400000l, actual);
|
||||||
|
|
||||||
BigDecimal f2 = rs.getBigDecimal("f2");
|
BigDecimal f2 = rs.getBigDecimal("f2");
|
||||||
Assert.assertEquals(1, f2.intValue());
|
Assert.assertEquals(1, f2.intValue());
|
||||||
|
@ -119,7 +119,7 @@ public class RestfulResultSetTest {
|
||||||
@Test
|
@Test
|
||||||
public void getBytes() throws SQLException {
|
public void getBytes() throws SQLException {
|
||||||
byte[] f1 = rs.getBytes("f1");
|
byte[] f1 = rs.getBytes("f1");
|
||||||
Assert.assertEquals("2021-01-01 00:00:00.0", new String(f1));
|
Assert.assertEquals("2021-01-01 00:00:00.000", new String(f1));
|
||||||
|
|
||||||
byte[] f2 = rs.getBytes("f2");
|
byte[] f2 = rs.getBytes("f2");
|
||||||
Assert.assertEquals(1, Ints.fromByteArray(f2));
|
Assert.assertEquals(1, Ints.fromByteArray(f2));
|
||||||
|
|
|
@ -120,11 +120,18 @@ enum MODE {
|
||||||
MODE_BUT
|
MODE_BUT
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum enum_INSERT_MODE {
|
enum enum_TAOS_INTERFACE {
|
||||||
|
TAOSC_IFACE,
|
||||||
|
REST_IFACE,
|
||||||
|
STMT_IFACE,
|
||||||
|
INTERFACE_BUT
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum enum_PROGRESSIVE_OR_INTERLACE {
|
||||||
PROGRESSIVE_INSERT_MODE,
|
PROGRESSIVE_INSERT_MODE,
|
||||||
INTERLACE_INSERT_MODE,
|
INTERLACE_INSERT_MODE,
|
||||||
INVALID_INSERT_MODE
|
INVALID_INSERT_MODE
|
||||||
} INSERT_MODE;
|
} PROG_OR_INTERLACE_MODE;
|
||||||
|
|
||||||
typedef enum enumQUERY_TYPE {
|
typedef enum enumQUERY_TYPE {
|
||||||
NO_INSERT_TYPE,
|
NO_INSERT_TYPE,
|
||||||
|
@ -188,6 +195,7 @@ typedef struct SArguments_S {
|
||||||
uint32_t test_mode;
|
uint32_t test_mode;
|
||||||
char * host;
|
char * host;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
|
uint16_t iface;
|
||||||
char * user;
|
char * user;
|
||||||
char * password;
|
char * password;
|
||||||
char * database;
|
char * database;
|
||||||
|
@ -238,7 +246,7 @@ typedef struct SSuperTable_S {
|
||||||
uint8_t autoCreateTable; // 0: create sub table, 1: auto create sub table
|
uint8_t autoCreateTable; // 0: create sub table, 1: auto create sub table
|
||||||
char childTblPrefix[MAX_TB_NAME_SIZE];
|
char childTblPrefix[MAX_TB_NAME_SIZE];
|
||||||
char dataSource[MAX_TB_NAME_SIZE+1]; // rand_gen or sample
|
char dataSource[MAX_TB_NAME_SIZE+1]; // rand_gen or sample
|
||||||
char insertMode[MAX_TB_NAME_SIZE]; // taosc, rest
|
uint16_t insertMode; // 0: taosc, 1: rest, 2: stmt
|
||||||
int64_t childTblLimit;
|
int64_t childTblLimit;
|
||||||
uint64_t childTblOffset;
|
uint64_t childTblOffset;
|
||||||
|
|
||||||
|
@ -405,6 +413,7 @@ typedef struct SQueryMetaInfo_S {
|
||||||
|
|
||||||
typedef struct SThreadInfo_S {
|
typedef struct SThreadInfo_S {
|
||||||
TAOS * taos;
|
TAOS * taos;
|
||||||
|
TAOS_STMT *stmt;
|
||||||
int threadID;
|
int threadID;
|
||||||
char db_name[MAX_DB_NAME_SIZE+1];
|
char db_name[MAX_DB_NAME_SIZE+1];
|
||||||
uint32_t time_precision;
|
uint32_t time_precision;
|
||||||
|
@ -418,6 +427,7 @@ typedef struct SThreadInfo_S {
|
||||||
char* cols;
|
char* cols;
|
||||||
bool use_metric;
|
bool use_metric;
|
||||||
SSuperTable* superTblInfo;
|
SSuperTable* superTblInfo;
|
||||||
|
char *buffer; // sql cmd buffer
|
||||||
|
|
||||||
// for async insert
|
// for async insert
|
||||||
tsem_t lock_sem;
|
tsem_t lock_sem;
|
||||||
|
@ -536,6 +546,7 @@ SArguments g_args = {
|
||||||
0, // test_mode
|
0, // test_mode
|
||||||
"127.0.0.1", // host
|
"127.0.0.1", // host
|
||||||
6030, // port
|
6030, // port
|
||||||
|
TAOSC_IFACE, // iface
|
||||||
"root", // user
|
"root", // user
|
||||||
#ifdef _TD_POWER_
|
#ifdef _TD_POWER_
|
||||||
"powerdb", // password
|
"powerdb", // password
|
||||||
|
@ -652,6 +663,8 @@ static void printHelp() {
|
||||||
"The host to connect to TDengine. Default is localhost.");
|
"The host to connect to TDengine. Default is localhost.");
|
||||||
printf("%s%s%s%s\n", indent, "-p", indent,
|
printf("%s%s%s%s\n", indent, "-p", indent,
|
||||||
"The TCP/IP port number to use for the connection. Default is 0.");
|
"The TCP/IP port number to use for the connection. Default is 0.");
|
||||||
|
printf("%s%s%s%s\n", indent, "-I", indent,
|
||||||
|
"The interface (taosc, rest, and stmt) taosdemo uses. Default is 'taosc'.");
|
||||||
printf("%s%s%s%s\n", indent, "-d", indent,
|
printf("%s%s%s%s\n", indent, "-d", indent,
|
||||||
"Destination database. Default is 'test'.");
|
"Destination database. Default is 'test'.");
|
||||||
printf("%s%s%s%s\n", indent, "-a", indent,
|
printf("%s%s%s%s\n", indent, "-a", indent,
|
||||||
|
@ -740,6 +753,23 @@ static void parse_args(int argc, char *argv[], SArguments *arguments) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
arguments->port = atoi(argv[++i]);
|
arguments->port = atoi(argv[++i]);
|
||||||
|
} else if (strcmp(argv[i], "-I") == 0) {
|
||||||
|
if (argc == i+1) {
|
||||||
|
printHelp();
|
||||||
|
errorPrint("%s", "\n\t-I need a valid string following!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
if (0 == strcasecmp(argv[i], "taosc")) {
|
||||||
|
arguments->iface = TAOSC_IFACE;
|
||||||
|
} else if (0 == strcasecmp(argv[i], "rest")) {
|
||||||
|
arguments->iface = REST_IFACE;
|
||||||
|
} else if (0 == strcasecmp(argv[i], "stmt")) {
|
||||||
|
arguments->iface = STMT_IFACE;
|
||||||
|
} else {
|
||||||
|
errorPrint("%s", "\n\t-I need a valid string following!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
} else if (strcmp(argv[i], "-u") == 0) {
|
} else if (strcmp(argv[i], "-u") == 0) {
|
||||||
if (argc == i+1) {
|
if (argc == i+1) {
|
||||||
printHelp();
|
printHelp();
|
||||||
|
@ -997,7 +1027,8 @@ static void parse_args(int argc, char *argv[], SArguments *arguments) {
|
||||||
arguments->port );
|
arguments->port );
|
||||||
printf("# User: %s\n", arguments->user);
|
printf("# User: %s\n", arguments->user);
|
||||||
printf("# Password: %s\n", arguments->password);
|
printf("# Password: %s\n", arguments->password);
|
||||||
printf("# Use metric: %s\n", arguments->use_metric ? "true" : "false");
|
printf("# Use metric: %s\n",
|
||||||
|
arguments->use_metric ? "true" : "false");
|
||||||
if (*(arguments->datatype)) {
|
if (*(arguments->datatype)) {
|
||||||
printf("# Specified data type: ");
|
printf("# Specified data type: ");
|
||||||
for (int i = 0; i < MAX_NUM_DATATYPE; i++)
|
for (int i = 0; i < MAX_NUM_DATATYPE; i++)
|
||||||
|
@ -1059,7 +1090,7 @@ static int queryDbExec(TAOS *taos, char *command, QUERY_TYPE type, bool quiet) {
|
||||||
TAOS_RES *res = NULL;
|
TAOS_RES *res = NULL;
|
||||||
int32_t code = -1;
|
int32_t code = -1;
|
||||||
|
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5 /* retry */; i++) {
|
||||||
if (NULL != res) {
|
if (NULL != res) {
|
||||||
taos_free_result(res);
|
taos_free_result(res);
|
||||||
res = NULL;
|
res = NULL;
|
||||||
|
@ -1105,7 +1136,6 @@ static void appendResultBufToFile(char *resultBuf, char *resultFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fprintf(fp, "%s", resultBuf);
|
fprintf(fp, "%s", resultBuf);
|
||||||
tmfclose(fp);
|
tmfclose(fp);
|
||||||
}
|
}
|
||||||
|
@ -1146,8 +1176,8 @@ static void appendResultToFile(TAOS_RES *res, char* resultFile) {
|
||||||
free(databuf);
|
free(databuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void selectAndGetResult(threadInfo *pThreadInfo, char *command, char* resultFile)
|
static void selectAndGetResult(
|
||||||
{
|
threadInfo *pThreadInfo, char *command, char* resultFile) {
|
||||||
if (0 == strncasecmp(g_queryInfo.queryMode, "taosc", strlen("taosc"))) {
|
if (0 == strncasecmp(g_queryInfo.queryMode, "taosc", strlen("taosc"))) {
|
||||||
TAOS_RES *res = taos_query(pThreadInfo->taos, command);
|
TAOS_RES *res = taos_query(pThreadInfo->taos, command);
|
||||||
if (res == NULL || taos_errno(res) != 0) {
|
if (res == NULL || taos_errno(res) != 0) {
|
||||||
|
@ -1291,6 +1321,8 @@ static void init_rand_data() {
|
||||||
static int printfInsertMeta() {
|
static int printfInsertMeta() {
|
||||||
SHOW_PARSE_RESULT_START();
|
SHOW_PARSE_RESULT_START();
|
||||||
|
|
||||||
|
printf("interface: \033[33m%s\033[0m\n",
|
||||||
|
(g_args.iface==TAOSC_IFACE)?"taosc":(g_args.iface==REST_IFACE)?"rest":"stmt");
|
||||||
printf("host: \033[33m%s:%u\033[0m\n", g_Dbs.host, g_Dbs.port);
|
printf("host: \033[33m%s:%u\033[0m\n", g_Dbs.host, g_Dbs.port);
|
||||||
printf("user: \033[33m%s\033[0m\n", g_Dbs.user);
|
printf("user: \033[33m%s\033[0m\n", g_Dbs.user);
|
||||||
printf("password: \033[33m%s\033[0m\n", g_Dbs.password);
|
printf("password: \033[33m%s\033[0m\n", g_Dbs.password);
|
||||||
|
@ -1395,7 +1427,8 @@ static int printfInsertMeta() {
|
||||||
printf(" dataSource: \033[33m%s\033[0m\n",
|
printf(" dataSource: \033[33m%s\033[0m\n",
|
||||||
g_Dbs.db[i].superTbls[j].dataSource);
|
g_Dbs.db[i].superTbls[j].dataSource);
|
||||||
printf(" insertMode: \033[33m%s\033[0m\n",
|
printf(" insertMode: \033[33m%s\033[0m\n",
|
||||||
g_Dbs.db[i].superTbls[j].insertMode);
|
(g_Dbs.db[i].superTbls[j].insertMode==TAOSC_IFACE)?"taosc":
|
||||||
|
(g_Dbs.db[i].superTbls[j].insertMode==REST_IFACE)?"rest":"stmt");
|
||||||
if (g_Dbs.db[i].superTbls[j].childTblLimit > 0) {
|
if (g_Dbs.db[i].superTbls[j].childTblLimit > 0) {
|
||||||
printf(" childTblLimit: \033[33m%"PRId64"\033[0m\n",
|
printf(" childTblLimit: \033[33m%"PRId64"\033[0m\n",
|
||||||
g_Dbs.db[i].superTbls[j].childTblLimit);
|
g_Dbs.db[i].superTbls[j].childTblLimit);
|
||||||
|
@ -1550,8 +1583,8 @@ static void printfInsertMetaToFile(FILE* fp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, " super table count: %"PRIu64"\n", g_Dbs.db[i].superTblCount);
|
fprintf(fp, " super table count: %"PRIu64"\n", g_Dbs.db[i].superTblCount);
|
||||||
for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) {
|
for (uint64_t j = 0; j < g_Dbs.db[i].superTblCount; j++) {
|
||||||
fprintf(fp, " super table[%d]:\n", j);
|
fprintf(fp, " super table[%"PRIu64"]:\n", j);
|
||||||
|
|
||||||
fprintf(fp, " stbName: %s\n", g_Dbs.db[i].superTbls[j].sTblName);
|
fprintf(fp, " stbName: %s\n", g_Dbs.db[i].superTbls[j].sTblName);
|
||||||
|
|
||||||
|
@ -1578,7 +1611,8 @@ static void printfInsertMetaToFile(FILE* fp) {
|
||||||
fprintf(fp, " dataSource: %s\n",
|
fprintf(fp, " dataSource: %s\n",
|
||||||
g_Dbs.db[i].superTbls[j].dataSource);
|
g_Dbs.db[i].superTbls[j].dataSource);
|
||||||
fprintf(fp, " insertMode: %s\n",
|
fprintf(fp, " insertMode: %s\n",
|
||||||
g_Dbs.db[i].superTbls[j].insertMode);
|
(g_Dbs.db[i].superTbls[j].insertMode==TAOSC_IFACE)?"taosc":
|
||||||
|
(g_Dbs.db[i].superTbls[j].insertMode==REST_IFACE)?"rest":"stmt");
|
||||||
fprintf(fp, " insertRows: %"PRId64"\n",
|
fprintf(fp, " insertRows: %"PRId64"\n",
|
||||||
g_Dbs.db[i].superTbls[j].insertRows);
|
g_Dbs.db[i].superTbls[j].insertRows);
|
||||||
fprintf(fp, " interlace rows: %"PRIu64"\n",
|
fprintf(fp, " interlace rows: %"PRIu64"\n",
|
||||||
|
@ -2749,7 +2783,7 @@ static int createDatabasesAndStables() {
|
||||||
|
|
||||||
int validStbCount = 0;
|
int validStbCount = 0;
|
||||||
|
|
||||||
for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) {
|
for (uint64_t j = 0; j < g_Dbs.db[i].superTblCount; j++) {
|
||||||
sprintf(command, "describe %s.%s;", g_Dbs.db[i].dbName,
|
sprintf(command, "describe %s.%s;", g_Dbs.db[i].dbName,
|
||||||
g_Dbs.db[i].superTbls[j].sTblName);
|
g_Dbs.db[i].superTbls[j].sTblName);
|
||||||
verbosePrint("%s() %d command: %s\n", __func__, __LINE__, command);
|
verbosePrint("%s() %d command: %s\n", __func__, __LINE__, command);
|
||||||
|
@ -2761,7 +2795,7 @@ static int createDatabasesAndStables() {
|
||||||
&g_Dbs.db[i].superTbls[j]);
|
&g_Dbs.db[i].superTbls[j]);
|
||||||
|
|
||||||
if (0 != ret) {
|
if (0 != ret) {
|
||||||
errorPrint("create super table %d failed!\n\n", j);
|
errorPrint("create super table %"PRIu64" failed!\n\n", j);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2789,7 +2823,7 @@ static void* createTable(void *sarg)
|
||||||
threadInfo *pThreadInfo = (threadInfo *)sarg;
|
threadInfo *pThreadInfo = (threadInfo *)sarg;
|
||||||
SSuperTable* superTblInfo = pThreadInfo->superTblInfo;
|
SSuperTable* superTblInfo = pThreadInfo->superTblInfo;
|
||||||
|
|
||||||
int64_t lastPrintTime = taosGetTimestampMs();
|
uint64_t lastPrintTime = taosGetTimestampMs();
|
||||||
|
|
||||||
int buff_len;
|
int buff_len;
|
||||||
buff_len = BUFFER_SIZE / 8;
|
buff_len = BUFFER_SIZE / 8;
|
||||||
|
@ -2864,7 +2898,7 @@ static void* createTable(void *sarg)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t currentPrintTime = taosGetTimestampMs();
|
uint64_t currentPrintTime = taosGetTimestampMs();
|
||||||
if (currentPrintTime - lastPrintTime > 30*1000) {
|
if (currentPrintTime - lastPrintTime > 30*1000) {
|
||||||
printf("thread[%d] already create %"PRIu64" - %"PRIu64" tables\n",
|
printf("thread[%d] already create %"PRIu64" - %"PRIu64" tables\n",
|
||||||
pThreadInfo->threadID, pThreadInfo->start_table_from, i);
|
pThreadInfo->threadID, pThreadInfo->start_table_from, i);
|
||||||
|
@ -2888,7 +2922,7 @@ static int startMultiThreadCreateChildTable(
|
||||||
char* db_name, SSuperTable* superTblInfo) {
|
char* db_name, SSuperTable* superTblInfo) {
|
||||||
|
|
||||||
pthread_t *pids = malloc(threads * sizeof(pthread_t));
|
pthread_t *pids = malloc(threads * sizeof(pthread_t));
|
||||||
threadInfo *infos = malloc(threads * sizeof(threadInfo));
|
threadInfo *infos = calloc(1, threads * sizeof(threadInfo));
|
||||||
|
|
||||||
if ((NULL == pids) || (NULL == infos)) {
|
if ((NULL == pids) || (NULL == infos)) {
|
||||||
printf("malloc failed\n");
|
printf("malloc failed\n");
|
||||||
|
@ -2908,7 +2942,7 @@ static int startMultiThreadCreateChildTable(
|
||||||
int64_t b = 0;
|
int64_t b = 0;
|
||||||
b = ntables % threads;
|
b = ntables % threads;
|
||||||
|
|
||||||
for (int64_t i = 0; i < threads; i++) {
|
for (int i = 0; i < threads; i++) {
|
||||||
threadInfo *t_info = infos + i;
|
threadInfo *t_info = infos + i;
|
||||||
t_info->threadID = i;
|
t_info->threadID = i;
|
||||||
tstrncpy(t_info->db_name, db_name, MAX_DB_NAME_SIZE);
|
tstrncpy(t_info->db_name, db_name, MAX_DB_NAME_SIZE);
|
||||||
|
@ -2961,7 +2995,7 @@ static void createChildTables() {
|
||||||
if (g_Dbs.use_metric) {
|
if (g_Dbs.use_metric) {
|
||||||
if (g_Dbs.db[i].superTblCount > 0) {
|
if (g_Dbs.db[i].superTblCount > 0) {
|
||||||
// with super table
|
// with super table
|
||||||
for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) {
|
for (uint64_t j = 0; j < g_Dbs.db[i].superTblCount; j++) {
|
||||||
if ((AUTO_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable)
|
if ((AUTO_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable)
|
||||||
|| (TBL_ALREADY_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists)) {
|
|| (TBL_ALREADY_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -3082,10 +3116,12 @@ static int readTagFromCsvFileToMem(SSuperTable * superTblInfo) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
int readSampleFromJsonFileToMem(SSuperTable * superTblInfo) {
|
int readSampleFromJsonFileToMem(SSuperTable * superTblInfo) {
|
||||||
// TODO
|
// TODO
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read 10000 lines at most. If more than 10000 lines, continue to read after using
|
Read 10000 lines at most. If more than 10000 lines, continue to read after using
|
||||||
|
@ -3785,15 +3821,24 @@ static bool getMetaFromInsertJsonFile(cJSON* root) {
|
||||||
goto PARSE_OVER;
|
goto PARSE_OVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
cJSON *insertMode = cJSON_GetObjectItem(stbInfo, "insert_mode"); // taosc , rest
|
cJSON *insertMode = cJSON_GetObjectItem(stbInfo, "insert_mode"); // taosc , rest, stmt
|
||||||
if (insertMode && insertMode->type == cJSON_String
|
if (insertMode && insertMode->type == cJSON_String
|
||||||
&& insertMode->valuestring != NULL) {
|
&& insertMode->valuestring != NULL) {
|
||||||
tstrncpy(g_Dbs.db[i].superTbls[j].insertMode,
|
if (0 == strcasecmp(insertMode->valuestring, "taosc")) {
|
||||||
insertMode->valuestring, MAX_DB_NAME_SIZE);
|
g_Dbs.db[i].superTbls[j].insertMode = TAOSC_IFACE;
|
||||||
|
} else if (0 == strcasecmp(insertMode->valuestring, "rest")) {
|
||||||
|
g_Dbs.db[i].superTbls[j].insertMode = REST_IFACE;
|
||||||
|
} else if (0 == strcasecmp(insertMode->valuestring, "stmt")) {
|
||||||
|
g_Dbs.db[i].superTbls[j].insertMode = STMT_IFACE;
|
||||||
|
} else {
|
||||||
|
errorPrint("%s() LN%d, failed to read json, insert_mode %s not recognized\n",
|
||||||
|
__func__, __LINE__, insertMode->valuestring);
|
||||||
|
goto PARSE_OVER;
|
||||||
|
}
|
||||||
} else if (!insertMode) {
|
} else if (!insertMode) {
|
||||||
tstrncpy(g_Dbs.db[i].superTbls[j].insertMode, "taosc", MAX_DB_NAME_SIZE);
|
g_Dbs.db[i].superTbls[j].insertMode = TAOSC_IFACE;
|
||||||
} else {
|
} else {
|
||||||
printf("ERROR: failed to read json, insert_mode not found\n");
|
errorPrint("%s", "failed to read json, insert_mode not found\n");
|
||||||
goto PARSE_OVER;
|
goto PARSE_OVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4510,7 +4555,7 @@ static void prepareSampleData() {
|
||||||
static void postFreeResource() {
|
static void postFreeResource() {
|
||||||
tmfclose(g_fpOfInsertResult);
|
tmfclose(g_fpOfInsertResult);
|
||||||
for (int i = 0; i < g_Dbs.dbCount; i++) {
|
for (int i = 0; i < g_Dbs.dbCount; i++) {
|
||||||
for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) {
|
for (uint64_t j = 0; j < g_Dbs.db[i].superTblCount; j++) {
|
||||||
if (0 != g_Dbs.db[i].superTbls[j].colsOfCreateChildTable) {
|
if (0 != g_Dbs.db[i].superTbls[j].colsOfCreateChildTable) {
|
||||||
free(g_Dbs.db[i].superTbls[j].colsOfCreateChildTable);
|
free(g_Dbs.db[i].superTbls[j].colsOfCreateChildTable);
|
||||||
g_Dbs.db[i].superTbls[j].colsOfCreateChildTable = NULL;
|
g_Dbs.db[i].superTbls[j].colsOfCreateChildTable = NULL;
|
||||||
|
@ -4715,32 +4760,43 @@ static int prepareSampleDataForSTable(SSuperTable *superTblInfo) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t execInsert(threadInfo *pThreadInfo, char *buffer, uint64_t k)
|
static int64_t execInsert(threadInfo *pThreadInfo, uint64_t k)
|
||||||
{
|
{
|
||||||
int affectedRows;
|
int affectedRows;
|
||||||
SSuperTable* superTblInfo = pThreadInfo->superTblInfo;
|
SSuperTable* superTblInfo = pThreadInfo->superTblInfo;
|
||||||
|
|
||||||
verbosePrint("[%d] %s() LN%d %s\n", pThreadInfo->threadID,
|
verbosePrint("[%d] %s() LN%d %s\n", pThreadInfo->threadID,
|
||||||
__func__, __LINE__, buffer);
|
__func__, __LINE__, pThreadInfo->buffer);
|
||||||
if (superTblInfo) {
|
if (superTblInfo) {
|
||||||
if (0 == strncasecmp(superTblInfo->insertMode, "taosc", strlen("taosc"))) {
|
if (superTblInfo->insertMode == TAOSC_IFACE) {
|
||||||
affectedRows = queryDbExec(pThreadInfo->taos, buffer, INSERT_TYPE, false);
|
affectedRows = queryDbExec(
|
||||||
} else if (0 == strncasecmp(superTblInfo->insertMode, "rest", strlen("rest"))) {
|
pThreadInfo->taos,
|
||||||
|
pThreadInfo->buffer, INSERT_TYPE, false);
|
||||||
|
} else if (superTblInfo->insertMode == REST_IFACE) {
|
||||||
if (0 != postProceSql(g_Dbs.host, &g_Dbs.serv_addr, g_Dbs.port,
|
if (0 != postProceSql(g_Dbs.host, &g_Dbs.serv_addr, g_Dbs.port,
|
||||||
buffer, NULL /* not set result file */)) {
|
pThreadInfo->buffer, NULL /* not set result file */)) {
|
||||||
affectedRows = -1;
|
affectedRows = -1;
|
||||||
printf("========restful return fail, threadID[%d]\n",
|
printf("========restful return fail, threadID[%d]\n",
|
||||||
pThreadInfo->threadID);
|
pThreadInfo->threadID);
|
||||||
} else {
|
} else {
|
||||||
affectedRows = k;
|
affectedRows = k;
|
||||||
}
|
}
|
||||||
|
} else if (superTblInfo->insertMode == STMT_IFACE) {
|
||||||
|
debugPrint("%s() LN%d, stmt=%p", __func__, __LINE__, pThreadInfo->stmt);
|
||||||
|
if (0 != taos_stmt_execute(pThreadInfo->stmt)) {
|
||||||
|
errorPrint("%s() LN%d, failied to execute insert statement\n",
|
||||||
|
__func__, __LINE__);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
affectedRows = k;
|
||||||
} else {
|
} else {
|
||||||
errorPrint("%s() LN%d: unknown insert mode: %s\n",
|
errorPrint("%s() LN%d: unknown insert mode: %d\n",
|
||||||
__func__, __LINE__, superTblInfo->insertMode);
|
__func__, __LINE__, superTblInfo->insertMode);
|
||||||
affectedRows = 0;
|
affectedRows = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
affectedRows = queryDbExec(pThreadInfo->taos, buffer, INSERT_TYPE, false);
|
affectedRows = queryDbExec(pThreadInfo->taos, pThreadInfo->buffer, INSERT_TYPE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return affectedRows;
|
return affectedRows;
|
||||||
|
@ -5086,20 +5142,17 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) {
|
||||||
if (interlaceRows > g_args.num_of_RPR)
|
if (interlaceRows > g_args.num_of_RPR)
|
||||||
interlaceRows = g_args.num_of_RPR;
|
interlaceRows = g_args.num_of_RPR;
|
||||||
|
|
||||||
int insertMode;
|
int progOrInterlace;
|
||||||
|
|
||||||
if (interlaceRows > 0) {
|
if (interlaceRows > 0) {
|
||||||
insertMode = INTERLACE_INSERT_MODE;
|
progOrInterlace= INTERLACE_INSERT_MODE;
|
||||||
} else {
|
} else {
|
||||||
insertMode = PROGRESSIVE_INSERT_MODE;
|
progOrInterlace = PROGRESSIVE_INSERT_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: prompt tbl count multple interlace rows and batch
|
|
||||||
//
|
|
||||||
|
|
||||||
uint64_t maxSqlLen = superTblInfo?superTblInfo->maxSqlLen:g_args.max_sql_len;
|
uint64_t maxSqlLen = superTblInfo?superTblInfo->maxSqlLen:g_args.max_sql_len;
|
||||||
char* buffer = calloc(maxSqlLen, 1);
|
pThreadInfo->buffer = calloc(maxSqlLen, 1);
|
||||||
if (NULL == buffer) {
|
if (NULL == pThreadInfo->buffer) {
|
||||||
errorPrint( "%s() LN%d, Failed to alloc %"PRIu64" Bytes, reason:%s\n",
|
errorPrint( "%s() LN%d, Failed to alloc %"PRIu64" Bytes, reason:%s\n",
|
||||||
__func__, __LINE__, maxSqlLen, strerror(errno));
|
__func__, __LINE__, maxSqlLen, strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5152,10 +5205,10 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) {
|
||||||
flagSleep = false;
|
flagSleep = false;
|
||||||
}
|
}
|
||||||
// generate data
|
// generate data
|
||||||
memset(buffer, 0, maxSqlLen);
|
memset(pThreadInfo->buffer, 0, maxSqlLen);
|
||||||
uint64_t remainderBufLen = maxSqlLen;
|
uint64_t remainderBufLen = maxSqlLen;
|
||||||
|
|
||||||
char *pstr = buffer;
|
char *pstr = pThreadInfo->buffer;
|
||||||
|
|
||||||
int len = snprintf(pstr, nInsertBufLen + 1, "%s", strInsertInto);
|
int len = snprintf(pstr, nInsertBufLen + 1, "%s", strInsertInto);
|
||||||
pstr += len;
|
pstr += len;
|
||||||
|
@ -5168,7 +5221,7 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) {
|
||||||
if (0 == strlen(tableName)) {
|
if (0 == strlen(tableName)) {
|
||||||
errorPrint("[%d] %s() LN%d, getTableName return null\n",
|
errorPrint("[%d] %s() LN%d, getTableName return null\n",
|
||||||
pThreadInfo->threadID, __func__, __LINE__);
|
pThreadInfo->threadID, __func__, __LINE__);
|
||||||
free(buffer);
|
free(pThreadInfo->buffer);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5200,7 +5253,7 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) {
|
||||||
pThreadInfo->threadID, __func__, __LINE__,
|
pThreadInfo->threadID, __func__, __LINE__,
|
||||||
batchPerTbl, recOfBatch);
|
batchPerTbl, recOfBatch);
|
||||||
|
|
||||||
if (insertMode == INTERLACE_INSERT_MODE) {
|
if (progOrInterlace == INTERLACE_INSERT_MODE) {
|
||||||
if (tableSeq == pThreadInfo->start_table_from + pThreadInfo->ntables) {
|
if (tableSeq == pThreadInfo->start_table_from + pThreadInfo->ntables) {
|
||||||
// turn to first table
|
// turn to first table
|
||||||
tableSeq = pThreadInfo->start_table_from;
|
tableSeq = pThreadInfo->start_table_from;
|
||||||
|
@ -5234,7 +5287,7 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) {
|
||||||
pThreadInfo->threadID, __func__, __LINE__, recOfBatch,
|
pThreadInfo->threadID, __func__, __LINE__, recOfBatch,
|
||||||
pThreadInfo->totalInsertRows);
|
pThreadInfo->totalInsertRows);
|
||||||
verbosePrint("[%d] %s() LN%d, buffer=%s\n",
|
verbosePrint("[%d] %s() LN%d, buffer=%s\n",
|
||||||
pThreadInfo->threadID, __func__, __LINE__, buffer);
|
pThreadInfo->threadID, __func__, __LINE__, pThreadInfo->buffer);
|
||||||
|
|
||||||
startTs = taosGetTimestampMs();
|
startTs = taosGetTimestampMs();
|
||||||
|
|
||||||
|
@ -5245,7 +5298,7 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) {
|
||||||
errorPrint("%s\n", "\tPlease check if the batch or the buffer length is proper value!\n");
|
errorPrint("%s\n", "\tPlease check if the batch or the buffer length is proper value!\n");
|
||||||
goto free_of_interlace;
|
goto free_of_interlace;
|
||||||
}
|
}
|
||||||
int64_t affectedRows = execInsert(pThreadInfo, buffer, recOfBatch);
|
int64_t affectedRows = execInsert(pThreadInfo, recOfBatch);
|
||||||
|
|
||||||
endTs = taosGetTimestampMs();
|
endTs = taosGetTimestampMs();
|
||||||
uint64_t delay = endTs - startTs;
|
uint64_t delay = endTs - startTs;
|
||||||
|
@ -5263,7 +5316,7 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) {
|
||||||
if (recOfBatch != affectedRows) {
|
if (recOfBatch != affectedRows) {
|
||||||
errorPrint("[%d] %s() LN%d execInsert insert %"PRIu64", affected rows: %"PRId64"\n%s\n",
|
errorPrint("[%d] %s() LN%d execInsert insert %"PRIu64", affected rows: %"PRId64"\n%s\n",
|
||||||
pThreadInfo->threadID, __func__, __LINE__,
|
pThreadInfo->threadID, __func__, __LINE__,
|
||||||
recOfBatch, affectedRows, buffer);
|
recOfBatch, affectedRows, pThreadInfo->buffer);
|
||||||
goto free_of_interlace;
|
goto free_of_interlace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5282,8 +5335,8 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) {
|
||||||
et = taosGetTimestampMs();
|
et = taosGetTimestampMs();
|
||||||
|
|
||||||
if (insert_interval > (et - st) ) {
|
if (insert_interval > (et - st) ) {
|
||||||
int sleepTime = insert_interval - (et -st);
|
uint64_t sleepTime = insert_interval - (et -st);
|
||||||
performancePrint("%s() LN%d sleep: %d ms for insert interval\n",
|
performancePrint("%s() LN%d sleep: %"PRId64" ms for insert interval\n",
|
||||||
__func__, __LINE__, sleepTime);
|
__func__, __LINE__, sleepTime);
|
||||||
taosMsleep(sleepTime); // ms
|
taosMsleep(sleepTime); // ms
|
||||||
sleepTimeTotal += insert_interval;
|
sleepTimeTotal += insert_interval;
|
||||||
|
@ -5292,7 +5345,7 @@ static void* syncWriteInterlace(threadInfo *pThreadInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
free_of_interlace:
|
free_of_interlace:
|
||||||
tmfree(buffer);
|
tmfree(pThreadInfo->buffer);
|
||||||
printStatPerThread(pThreadInfo);
|
printStatPerThread(pThreadInfo);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -5311,8 +5364,8 @@ static void* syncWriteProgressive(threadInfo *pThreadInfo) {
|
||||||
SSuperTable* superTblInfo = pThreadInfo->superTblInfo;
|
SSuperTable* superTblInfo = pThreadInfo->superTblInfo;
|
||||||
uint64_t maxSqlLen = superTblInfo?superTblInfo->maxSqlLen:g_args.max_sql_len;
|
uint64_t maxSqlLen = superTblInfo?superTblInfo->maxSqlLen:g_args.max_sql_len;
|
||||||
|
|
||||||
char* buffer = calloc(maxSqlLen, 1);
|
pThreadInfo->buffer = calloc(maxSqlLen, 1);
|
||||||
if (NULL == buffer) {
|
if (NULL == pThreadInfo->buffer) {
|
||||||
errorPrint( "Failed to alloc %"PRIu64" Bytes, reason:%s\n",
|
errorPrint( "Failed to alloc %"PRIu64" Bytes, reason:%s\n",
|
||||||
maxSqlLen,
|
maxSqlLen,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
@ -5358,7 +5411,7 @@ static void* syncWriteProgressive(threadInfo *pThreadInfo) {
|
||||||
pThreadInfo->threadID, tableSeq, tableName);
|
pThreadInfo->threadID, tableSeq, tableName);
|
||||||
|
|
||||||
int64_t remainderBufLen = maxSqlLen;
|
int64_t remainderBufLen = maxSqlLen;
|
||||||
char *pstr = buffer;
|
char *pstr = pThreadInfo->buffer;
|
||||||
int nInsertBufLen = strlen("insert into ");
|
int nInsertBufLen = strlen("insert into ");
|
||||||
|
|
||||||
int len = snprintf(pstr, nInsertBufLen + 1, "%s", "insert into ");
|
int len = snprintf(pstr, nInsertBufLen + 1, "%s", "insert into ");
|
||||||
|
@ -5381,7 +5434,7 @@ static void* syncWriteProgressive(threadInfo *pThreadInfo) {
|
||||||
|
|
||||||
startTs = taosGetTimestampMs();
|
startTs = taosGetTimestampMs();
|
||||||
|
|
||||||
int64_t affectedRows = execInsert(pThreadInfo, buffer, generated);
|
int64_t affectedRows = execInsert(pThreadInfo, generated);
|
||||||
|
|
||||||
endTs = taosGetTimestampMs();
|
endTs = taosGetTimestampMs();
|
||||||
uint64_t delay = endTs - startTs;
|
uint64_t delay = endTs - startTs;
|
||||||
|
@ -5440,7 +5493,7 @@ static void* syncWriteProgressive(threadInfo *pThreadInfo) {
|
||||||
} // tableSeq
|
} // tableSeq
|
||||||
|
|
||||||
free_of_progressive:
|
free_of_progressive:
|
||||||
tmfree(buffer);
|
tmfree(pThreadInfo->buffer);
|
||||||
printStatPerThread(pThreadInfo);
|
printStatPerThread(pThreadInfo);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -5579,15 +5632,6 @@ static int convertHostToServAddr(char *host, uint16_t port, struct sockaddr_in *
|
||||||
static void startMultiThreadInsertData(int threads, char* db_name,
|
static void startMultiThreadInsertData(int threads, char* db_name,
|
||||||
char* precision,SSuperTable* superTblInfo) {
|
char* precision,SSuperTable* superTblInfo) {
|
||||||
|
|
||||||
pthread_t *pids = malloc(threads * sizeof(pthread_t));
|
|
||||||
assert(pids != NULL);
|
|
||||||
|
|
||||||
threadInfo *infos = malloc(threads * sizeof(threadInfo));
|
|
||||||
assert(infos != NULL);
|
|
||||||
|
|
||||||
memset(pids, 0, threads * sizeof(pthread_t));
|
|
||||||
memset(infos, 0, threads * sizeof(threadInfo));
|
|
||||||
|
|
||||||
//TAOS* taos;
|
//TAOS* taos;
|
||||||
//if (0 == strncasecmp(superTblInfo->insertMode, "taosc", 5)) {
|
//if (0 == strncasecmp(superTblInfo->insertMode, "taosc", 5)) {
|
||||||
// taos = taos_connect(g_Dbs.host, g_Dbs.user, g_Dbs.password, db_name, g_Dbs.port);
|
// taos = taos_connect(g_Dbs.host, g_Dbs.user, g_Dbs.password, db_name, g_Dbs.port);
|
||||||
|
@ -5648,10 +5692,10 @@ static void startMultiThreadInsertData(int threads, char* db_name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TAOS* taos = taos_connect(
|
TAOS* taos0 = taos_connect(
|
||||||
g_Dbs.host, g_Dbs.user,
|
g_Dbs.host, g_Dbs.user,
|
||||||
g_Dbs.password, db_name, g_Dbs.port);
|
g_Dbs.password, db_name, g_Dbs.port);
|
||||||
if (NULL == taos) {
|
if (NULL == taos0) {
|
||||||
errorPrint("%s() LN%d, connect to server fail , reason: %s\n",
|
errorPrint("%s() LN%d, connect to server fail , reason: %s\n",
|
||||||
__func__, __LINE__, taos_errstr(NULL));
|
__func__, __LINE__, taos_errstr(NULL));
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
@ -5710,13 +5754,13 @@ static void startMultiThreadInsertData(int threads, char* db_name,
|
||||||
limit * TSDB_TABLE_NAME_LEN);
|
limit * TSDB_TABLE_NAME_LEN);
|
||||||
if (superTblInfo->childTblName == NULL) {
|
if (superTblInfo->childTblName == NULL) {
|
||||||
errorPrint("%s() LN%d, alloc memory failed!\n", __func__, __LINE__);
|
errorPrint("%s() LN%d, alloc memory failed!\n", __func__, __LINE__);
|
||||||
taos_close(taos);
|
taos_close(taos0);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t childTblCount;
|
int64_t childTblCount;
|
||||||
getChildNameOfSuperTableWithLimitAndOffset(
|
getChildNameOfSuperTableWithLimitAndOffset(
|
||||||
taos,
|
taos0,
|
||||||
db_name, superTblInfo->sTblName,
|
db_name, superTblInfo->sTblName,
|
||||||
&superTblInfo->childTblName, &childTblCount,
|
&superTblInfo->childTblName, &childTblCount,
|
||||||
limit,
|
limit,
|
||||||
|
@ -5726,7 +5770,7 @@ static void startMultiThreadInsertData(int threads, char* db_name,
|
||||||
startFrom = 0;
|
startFrom = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
taos_close(taos);
|
taos_close(taos0);
|
||||||
|
|
||||||
int64_t a = ntables / threads;
|
int64_t a = ntables / threads;
|
||||||
if (a < 1) {
|
if (a < 1) {
|
||||||
|
@ -5740,11 +5784,21 @@ static void startMultiThreadInsertData(int threads, char* db_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((superTblInfo)
|
if ((superTblInfo)
|
||||||
&& (0 == strncasecmp(superTblInfo->insertMode, "rest", strlen("rest")))) {
|
&& (superTblInfo->insertMode == REST_IFACE)) {
|
||||||
if (convertHostToServAddr(g_Dbs.host, g_Dbs.port, &(g_Dbs.serv_addr)) != 0)
|
if (convertHostToServAddr(g_Dbs.host, g_Dbs.port, &(g_Dbs.serv_addr)) != 0) {
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_t *pids = malloc(threads * sizeof(pthread_t));
|
||||||
|
assert(pids != NULL);
|
||||||
|
|
||||||
|
threadInfo *infos = calloc(1, threads * sizeof(threadInfo));
|
||||||
|
assert(infos != NULL);
|
||||||
|
|
||||||
|
memset(pids, 0, threads * sizeof(pthread_t));
|
||||||
|
memset(infos, 0, threads * sizeof(threadInfo));
|
||||||
|
|
||||||
for (int i = 0; i < threads; i++) {
|
for (int i = 0; i < threads; i++) {
|
||||||
threadInfo *t_info = infos + i;
|
threadInfo *t_info = infos + i;
|
||||||
t_info->threadID = i;
|
t_info->threadID = i;
|
||||||
|
@ -5756,17 +5810,32 @@ static void startMultiThreadInsertData(int threads, char* db_name,
|
||||||
t_info->minDelay = UINT64_MAX;
|
t_info->minDelay = UINT64_MAX;
|
||||||
|
|
||||||
if ((NULL == superTblInfo) ||
|
if ((NULL == superTblInfo) ||
|
||||||
(0 == strncasecmp(superTblInfo->insertMode, "taosc", 5))) {
|
(superTblInfo->insertMode != REST_IFACE)) {
|
||||||
//t_info->taos = taos;
|
//t_info->taos = taos;
|
||||||
t_info->taos = taos_connect(
|
t_info->taos = taos_connect(
|
||||||
g_Dbs.host, g_Dbs.user,
|
g_Dbs.host, g_Dbs.user,
|
||||||
g_Dbs.password, db_name, g_Dbs.port);
|
g_Dbs.password, db_name, g_Dbs.port);
|
||||||
if (NULL == t_info->taos) {
|
if (NULL == t_info->taos) {
|
||||||
errorPrint(
|
errorPrint(
|
||||||
"connect to server fail from insert sub thread, reason: %s\n",
|
"%s() LN%d, connect to server fail from insert sub thread, reason: %s\n",
|
||||||
|
__func__, __LINE__,
|
||||||
taos_errstr(NULL));
|
taos_errstr(NULL));
|
||||||
|
free(infos);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((superTblInfo) && (superTblInfo->insertMode == STMT_IFACE)) {
|
||||||
|
t_info->stmt = taos_stmt_init(t_info->taos);
|
||||||
|
if (NULL == t_info->stmt) {
|
||||||
|
errorPrint(
|
||||||
|
"%s() LN%d, failed init stmt, reason: %s\n",
|
||||||
|
__func__, __LINE__,
|
||||||
|
taos_errstr(NULL));
|
||||||
|
free(pids);
|
||||||
|
free(infos);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
t_info->taos = NULL;
|
t_info->taos = NULL;
|
||||||
}
|
}
|
||||||
|
@ -5806,6 +5875,10 @@ static void startMultiThreadInsertData(int threads, char* db_name,
|
||||||
threadInfo *t_info = infos + i;
|
threadInfo *t_info = infos + i;
|
||||||
|
|
||||||
tsem_destroy(&(t_info->lock_sem));
|
tsem_destroy(&(t_info->lock_sem));
|
||||||
|
|
||||||
|
if (t_info->stmt) {
|
||||||
|
taos_stmt_close(t_info->stmt);
|
||||||
|
}
|
||||||
taos_close(t_info->taos);
|
taos_close(t_info->taos);
|
||||||
|
|
||||||
debugPrint("%s() LN%d, [%d] totalInsert=%"PRIu64" totalAffected=%"PRIu64"\n",
|
debugPrint("%s() LN%d, [%d] totalInsert=%"PRIu64" totalAffected=%"PRIu64"\n",
|
||||||
|
@ -6083,7 +6156,7 @@ static int insertTestProcess() {
|
||||||
for (int i = 0; i < g_Dbs.dbCount; i++) {
|
for (int i = 0; i < g_Dbs.dbCount; i++) {
|
||||||
if (g_Dbs.use_metric) {
|
if (g_Dbs.use_metric) {
|
||||||
if (g_Dbs.db[i].superTblCount > 0) {
|
if (g_Dbs.db[i].superTblCount > 0) {
|
||||||
for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) {
|
for (uint64_t j = 0; j < g_Dbs.db[i].superTblCount; j++) {
|
||||||
|
|
||||||
SSuperTable* superTblInfo = &g_Dbs.db[i].superTbls[j];
|
SSuperTable* superTblInfo = &g_Dbs.db[i].superTbls[j];
|
||||||
|
|
||||||
|
@ -6878,7 +6951,7 @@ static void setParaFromArg(){
|
||||||
tstrncpy(g_Dbs.db[0].superTbls[0].childTblPrefix,
|
tstrncpy(g_Dbs.db[0].superTbls[0].childTblPrefix,
|
||||||
g_args.tb_prefix, MAX_TB_NAME_SIZE);
|
g_args.tb_prefix, MAX_TB_NAME_SIZE);
|
||||||
tstrncpy(g_Dbs.db[0].superTbls[0].dataSource, "rand", MAX_TB_NAME_SIZE);
|
tstrncpy(g_Dbs.db[0].superTbls[0].dataSource, "rand", MAX_TB_NAME_SIZE);
|
||||||
tstrncpy(g_Dbs.db[0].superTbls[0].insertMode, "taosc", MAX_TB_NAME_SIZE);
|
g_Dbs.db[0].superTbls[0].insertMode = g_args.iface;
|
||||||
tstrncpy(g_Dbs.db[0].superTbls[0].startTimestamp,
|
tstrncpy(g_Dbs.db[0].superTbls[0].startTimestamp,
|
||||||
"2017-07-14 10:40:00.000", MAX_TB_NAME_SIZE);
|
"2017-07-14 10:40:00.000", MAX_TB_NAME_SIZE);
|
||||||
g_Dbs.db[0].superTbls[0].timeStampStep = DEFAULT_TIMESTAMP_STEP;
|
g_Dbs.db[0].superTbls[0].timeStampStep = DEFAULT_TIMESTAMP_STEP;
|
||||||
|
|
|
@ -123,8 +123,9 @@ SConnObj *mnodeAccquireConn(int32_t connId, char *user, uint32_t ip, uint16_t po
|
||||||
if (/* pConn->ip != ip || */ pConn->port != port /* || strcmp(pConn->user, user) != 0 */) {
|
if (/* pConn->ip != ip || */ pConn->port != port /* || strcmp(pConn->user, user) != 0 */) {
|
||||||
mDebug("connId:%d, incoming conn user:%s ip:%s:%u, not match exist conn user:%s ip:%s:%u", connId, user,
|
mDebug("connId:%d, incoming conn user:%s ip:%s:%u, not match exist conn user:%s ip:%s:%u", connId, user,
|
||||||
taosIpStr(ip), port, pConn->user, taosIpStr(pConn->ip), pConn->port);
|
taosIpStr(ip), port, pConn->user, taosIpStr(pConn->ip), pConn->port);
|
||||||
taosCacheRelease(tsMnodeConnCache, (void **)&pConn, false);
|
pConn->port = port;
|
||||||
return NULL;
|
//taosCacheRelease(tsMnodeConnCache, (void **)&pConn, false);
|
||||||
|
//return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mDebug("connId:%d, is incoming, user:%s ip:%s:%u", connId, pConn->user, taosIpStr(pConn->ip), pConn->port);
|
// mDebug("connId:%d, is incoming, user:%s ip:%s:%u", connId, pConn->user, taosIpStr(pConn->ip), pConn->port);
|
||||||
|
|
|
@ -253,10 +253,6 @@ static int32_t mnodeProcessHeartBeatMsg(SMnodeMsg *pMsg) {
|
||||||
|
|
||||||
int32_t connId = htonl(pHBMsg->connId);
|
int32_t connId = htonl(pHBMsg->connId);
|
||||||
SConnObj *pConn = mnodeAccquireConn(connId, connInfo.user, connInfo.clientIp, connInfo.clientPort);
|
SConnObj *pConn = mnodeAccquireConn(connId, connInfo.user, connInfo.clientIp, connInfo.clientPort);
|
||||||
if (pConn == NULL) {
|
|
||||||
pHBMsg->pid = htonl(pHBMsg->pid);
|
|
||||||
pConn = mnodeCreateConn(connInfo.user, connInfo.clientIp, connInfo.clientPort, pHBMsg->pid, pHBMsg->appName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pConn == NULL) {
|
if (pConn == NULL) {
|
||||||
// do not close existing links, otherwise
|
// do not close existing links, otherwise
|
||||||
|
|
|
@ -115,6 +115,8 @@ int64_t genQueryId(void) {
|
||||||
|
|
||||||
uid |= sid;
|
uid |= sid;
|
||||||
|
|
||||||
|
qDebug("gen qid:0x%"PRIx64, uid);
|
||||||
|
|
||||||
return uid;
|
return uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1471,7 +1471,7 @@ static int32_t rpcCompressRpcMsg(char* pCont, int32_t contLen) {
|
||||||
* only the compressed size is less than the value of contLen - overhead, the compression is applied
|
* only the compressed size is less than the value of contLen - overhead, the compression is applied
|
||||||
* The first four bytes is set to 0, the second four bytes are utilized to keep the original length of message
|
* The first four bytes is set to 0, the second four bytes are utilized to keep the original length of message
|
||||||
*/
|
*/
|
||||||
if (compLen < contLen - overhead) {
|
if (compLen > 0 && compLen < contLen - overhead) {
|
||||||
SRpcComp *pComp = (SRpcComp *)pCont;
|
SRpcComp *pComp = (SRpcComp *)pCont;
|
||||||
pComp->reserved = 0;
|
pComp->reserved = 0;
|
||||||
pComp->contLen = htonl(contLen);
|
pComp->contLen = htonl(contLen);
|
||||||
|
|
|
@ -426,8 +426,8 @@ static int32_t walRestoreWalFile(SWal *pWal, void *pVnode, FWalWrite writeFp, ch
|
||||||
#endif
|
#endif
|
||||||
offset = offset + sizeof(SWalHead) + pHead->len;
|
offset = offset + sizeof(SWalHead) + pHead->len;
|
||||||
|
|
||||||
wTrace("vgId:%d, restore wal, fileId:%" PRId64 " hver:%" PRIu64 " wver:%" PRIu64 " len:%d", pWal->vgId,
|
wTrace("vgId:%d, restore wal, fileId:%" PRId64 " hver:%" PRIu64 " wver:%" PRIu64 " len:%d offset:%" PRId64,
|
||||||
fileId, pHead->version, pWal->version, pHead->len);
|
pWal->vgId, fileId, pHead->version, pWal->version, pHead->len, offset);
|
||||||
|
|
||||||
pWal->version = pHead->version;
|
pWal->version = pHead->version;
|
||||||
(*writeFp)(pVnode, pHead, TAOS_QTYPE_WAL, NULL);
|
(*writeFp)(pVnode, pHead, TAOS_QTYPE_WAL, NULL);
|
||||||
|
|
Loading…
Reference in New Issue