blob: 6cc0db318dedeac874ffff0f30cf838753fbd953 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.iotdb.jdbc;
import org.apache.iotdb.service.rpc.thrift.IClientRPCService.Iface;
import org.apache.thrift.TException;
import org.apache.tsfile.common.conf.TSFileConfig;
import org.apache.tsfile.utils.Binary;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class IoTDBPreparedStatement extends IoTDBStatement implements PreparedStatement {
private String sql;
private static final String METHOD_NOT_SUPPORTED_STRING = "Method not supported";
private static final Logger logger = LoggerFactory.getLogger(IoTDBPreparedStatement.class);
/** save the SQL parameters as (paramLoc,paramValue) pairs. */
private final Map<Integer, String> parameters = new HashMap<>();
IoTDBPreparedStatement(
IoTDBConnection connection, Iface client, Long sessionId, String sql, ZoneId zoneId)
throws SQLException {
super(connection, client, sessionId, zoneId);
this.sql = sql;
}
@Override
public void addBatch() throws SQLException {
super.addBatch(createCompleteSql(sql, parameters));
}
@Override
public void clearParameters() {
this.parameters.clear();
}
@Override
public boolean execute() throws SQLException {
return super.execute(createCompleteSql(sql, parameters));
}
@Override
public ResultSet executeQuery() throws SQLException {
return super.executeQuery(createCompleteSql(sql, parameters));
}
@Override
public int executeUpdate() throws SQLException {
return super.executeUpdate(createCompleteSql(sql, parameters));
}
@Override
public ResultSetMetaData getMetaData() throws SQLException {
return getResultSet().getMetaData();
}
@Override
public ParameterMetaData getParameterMetaData() {
return new ParameterMetaData() {
@Override
public int getParameterCount() {
return parameters.size();
}
@Override
public int isNullable(int param) {
return ParameterMetaData.parameterNullableUnknown;
}
@Override
public boolean isSigned(int param) {
try {
return Integer.parseInt(parameters.get(param)) < 0;
} catch (Exception e) {
return false;
}
}
@Override
public int getPrecision(int param) {
return parameters.get(param).length();
}
@Override
public int getScale(int param) {
try {
double d = Double.parseDouble(parameters.get(param));
if (d >= 1) { // we only need the fraction digits
d = d - (long) d;
}
if (d == 0) { // nothing to count
return 0;
}
d *= 10; // shifts 1 digit to left
int count = 1;
while (d - (long) d != 0) { // keeps shifting until there are no more fractions
d *= 10;
count++;
}
return count;
} catch (Exception e) {
return 0;
}
}
@Override
public int getParameterType(int param) {
return 0;
}
@Override
public String getParameterTypeName(int param) {
return null;
}
@Override
public String getParameterClassName(int param) {
return null;
}
@Override
public int getParameterMode(int param) {
return 0;
}
@Override
public <T> T unwrap(Class<T> iface) {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) {
return false;
}
};
}
@Override
public void setArray(int parameterIndex, Array x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setBlob(int parameterIndex, Blob x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream, long length)
throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setBoolean(int parameterIndex, boolean x) {
this.parameters.put(parameterIndex, Boolean.toString(x));
}
@Override
public void setByte(int parameterIndex, byte x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
Binary binary = new Binary(x);
this.parameters.put(parameterIndex, binary.getStringValue(TSFileConfig.STRING_CHARSET));
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, int length)
throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, long length)
throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setClob(int parameterIndex, Clob x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setClob(int parameterIndex, Reader reader) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setDate(int parameterIndex, Date x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setDouble(int parameterIndex, double x) {
this.parameters.put(parameterIndex, Double.toString(x));
}
@Override
public void setFloat(int parameterIndex, float x) {
this.parameters.put(parameterIndex, Float.toString(x));
}
@Override
public void setInt(int parameterIndex, int x) {
this.parameters.put(parameterIndex, Integer.toString(x));
}
@Override
public void setLong(int parameterIndex, long x) {
this.parameters.put(parameterIndex, Long.toString(x));
}
@Override
public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setNCharacterStream(int parameterIndex, Reader value, long length)
throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setNClob(int parameterIndex, NClob value) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setNClob(int parameterIndex, Reader reader) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setNString(int parameterIndex, String value) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setNull(int parameterIndex, int sqlType) throws SQLException {
throw new SQLException(Constant.PARAMETER_NOT_NULL);
}
@Override
public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
throw new SQLException(Constant.PARAMETER_NOT_NULL);
}
@Override
public void setObject(int parameterIndex, Object x) throws SQLException {
if (x instanceof String) {
setString(parameterIndex, (String) x);
} else if (x instanceof Integer) {
setInt(parameterIndex, (Integer) x);
} else if (x instanceof Long) {
setLong(parameterIndex, (Long) x);
} else if (x instanceof Float) {
setFloat(parameterIndex, (Float) x);
} else if (x instanceof Double) {
setDouble(parameterIndex, (Double) x);
} else if (x instanceof Boolean) {
setBoolean(parameterIndex, (Boolean) x);
} else if (x instanceof Timestamp) {
setTimestamp(parameterIndex, (Timestamp) x);
} else if (x instanceof Time) {
setTime(parameterIndex, (Time) x);
} else {
// Can't infer a type.
throw new SQLException(
String.format(
"Can''t infer the SQL type to use for an instance of %s. Use setObject() with"
+ " an explicit Types value to specify the type to use.",
x.getClass().getName()));
}
}
@Override
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
if (!(x instanceof BigDecimal)) {
setObject(parameterIndex, x, targetSqlType, 0);
} else {
setObject(parameterIndex, x, targetSqlType, ((BigDecimal) x).scale());
}
}
@SuppressWarnings({
"squid:S3776",
"squid:S6541"
}) // ignore Cognitive Complexity of methods should not be too high
// ignore Methods should not perform too many tasks (aka Brain method)
@Override
public void setObject(int parameterIndex, Object parameterObj, int targetSqlType, int scale)
throws SQLException {
if (parameterObj == null) {
setNull(parameterIndex, java.sql.Types.OTHER);
} else {
try {
switch (targetSqlType) {
case Types.BOOLEAN:
if (parameterObj instanceof Boolean) {
setBoolean(parameterIndex, ((Boolean) parameterObj).booleanValue());
break;
} else if (parameterObj instanceof String) {
if ("true".equalsIgnoreCase((String) parameterObj)
|| "Y".equalsIgnoreCase((String) parameterObj)) {
setBoolean(parameterIndex, true);
} else if ("false".equalsIgnoreCase((String) parameterObj)
|| "N".equalsIgnoreCase((String) parameterObj)) {
setBoolean(parameterIndex, false);
} else if (((String) parameterObj).matches("-?\\d+\\.?\\d*")) {
setBoolean(parameterIndex, !((String) parameterObj).matches("-?[0]+[.]*[0]*"));
} else {
throw new SQLException(
"No conversion from " + parameterObj + " to Types.BOOLEAN possible.");
}
break;
} else if (parameterObj instanceof Number) {
int intValue = ((Number) parameterObj).intValue();
setBoolean(parameterIndex, intValue != 0);
break;
} else {
throw new SQLException(
"No conversion from " + parameterObj + " to Types.BOOLEAN possible.");
}
case Types.BIT:
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
case Types.BIGINT:
case Types.REAL:
case Types.FLOAT:
case Types.DOUBLE:
case Types.DECIMAL:
case Types.NUMERIC:
setNumericObject(parameterIndex, parameterObj, targetSqlType, scale);
break;
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
if (parameterObj instanceof BigDecimal) {
setString(
parameterIndex,
StringUtils.fixDecimalExponent(
StringUtils.consistentToString((BigDecimal) parameterObj)));
} else {
setString(parameterIndex, parameterObj.toString());
}
break;
case Types.CLOB:
if (parameterObj instanceof java.sql.Clob) {
setClob(parameterIndex, (java.sql.Clob) parameterObj);
} else {
setString(parameterIndex, parameterObj.toString());
}
break;
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
case Types.BLOB:
throw new SQLException(Constant.PARAMETER_SUPPORTED);
case Types.DATE:
case Types.TIMESTAMP:
java.util.Date parameterAsDate;
if (parameterObj instanceof String) {
ParsePosition pp = new ParsePosition(0);
DateFormat sdf =
new SimpleDateFormat(getDateTimePattern((String) parameterObj, false), Locale.US);
parameterAsDate = sdf.parse((String) parameterObj, pp);
} else {
parameterAsDate = (Date) parameterObj;
}
switch (targetSqlType) {
case Types.DATE:
if (parameterAsDate instanceof java.sql.Date) {
setDate(parameterIndex, (java.sql.Date) parameterAsDate);
} else {
setDate(parameterIndex, new java.sql.Date(parameterAsDate.getTime()));
}
break;
case Types.TIMESTAMP:
if (parameterAsDate instanceof java.sql.Timestamp) {
setTimestamp(parameterIndex, (java.sql.Timestamp) parameterAsDate);
} else {
setTimestamp(parameterIndex, new java.sql.Timestamp(parameterAsDate.getTime()));
}
break;
default:
logger.error("No type was matched");
break;
}
break;
case Types.TIME:
if (parameterObj instanceof String) {
DateFormat sdf =
new SimpleDateFormat(getDateTimePattern((String) parameterObj, true), Locale.US);
setTime(parameterIndex, new Time(sdf.parse((String) parameterObj).getTime()));
} else if (parameterObj instanceof Timestamp) {
Timestamp xT = (Timestamp) parameterObj;
setTime(parameterIndex, new Time(xT.getTime()));
} else {
setTime(parameterIndex, (Time) parameterObj);
}
break;
case Types.OTHER:
throw new SQLException(Constant.PARAMETER_SUPPORTED); //
default:
throw new SQLException(Constant.PARAMETER_SUPPORTED); //
}
} catch (SQLException ex) {
throw ex;
} catch (Exception ex) {
throw new SQLException(Constant.PARAMETER_SUPPORTED); //
}
}
}
@SuppressWarnings({
"squid:S3776",
"squid:S6541"
}) // ignore Cognitive Complexity of methods should not be too high
// ignore Methods should not perform too many tasks (aka Brain method)
private final String getDateTimePattern(String dt, boolean toTime) throws Exception {
//
// Special case
//
int dtLength = (dt != null) ? dt.length() : 0;
if ((dtLength >= 8) && (dtLength <= 10)) {
int dashCount = 0;
boolean isDateOnly = true;
for (int i = 0; i < dtLength; i++) {
char c = dt.charAt(i);
if (!Character.isDigit(c) && (c != '-')) {
isDateOnly = false;
break;
}
if (c == '-') {
dashCount++;
}
}
if (isDateOnly && (dashCount == 2)) {
return "yyyy-MM-dd";
}
}
boolean colonsOnly = true;
for (int i = 0; i < dtLength; i++) {
char c = dt.charAt(i);
if (!Character.isDigit(c) && (c != ':')) {
colonsOnly = false;
break;
}
}
if (colonsOnly) {
return "HH:mm:ss";
}
int n;
int z;
int count;
int maxvecs;
char c;
char separator;
StringReader reader = new StringReader(dt + " ");
ArrayList<Object[]> vec = new ArrayList<>();
ArrayList<Object[]> vecRemovelist = new ArrayList<>();
Object[] nv = new Object[3];
Object[] v;
nv[0] = Character.valueOf('y');
nv[1] = new StringBuilder();
nv[2] = Integer.valueOf(0);
vec.add(nv);
if (toTime) {
nv = new Object[3];
nv[0] = Character.valueOf('h');
nv[1] = new StringBuilder();
nv[2] = Integer.valueOf(0);
vec.add(nv);
}
while ((z = reader.read()) != -1) {
separator = (char) z;
maxvecs = vec.size();
for (count = 0; count < maxvecs; count++) {
v = vec.get(count);
n = ((Integer) v[2]).intValue();
c = getSuccessor(((Character) v[0]).charValue(), n);
if (!Character.isLetterOrDigit(separator)) {
if ((c == ((Character) v[0]).charValue()) && (c != 'S')) {
vecRemovelist.add(v);
} else {
((StringBuilder) v[1]).append(separator);
if ((c == 'X') || (c == 'Y')) {
v[2] = Integer.valueOf(4);
}
}
} else {
if (c == 'X') {
c = 'y';
nv = new Object[3];
nv[1] = (new StringBuilder(((StringBuilder) v[1]).toString())).append('M');
nv[0] = Character.valueOf('M');
nv[2] = Integer.valueOf(1);
vec.add(nv);
} else if (c == 'Y') {
c = 'M';
nv = new Object[3];
nv[1] = (new StringBuilder(((StringBuilder) v[1]).toString())).append('d');
nv[0] = Character.valueOf('d');
nv[2] = Integer.valueOf(1);
vec.add(nv);
}
((StringBuilder) v[1]).append(c);
if (c == ((Character) v[0]).charValue()) {
v[2] = Integer.valueOf(n + 1);
} else {
v[0] = Character.valueOf(c);
v[2] = Integer.valueOf(1);
}
}
}
int size = vecRemovelist.size();
for (int i = 0; i < size; i++) {
v = vecRemovelist.get(i);
vec.remove(v);
}
vecRemovelist.clear();
}
int size = vec.size();
for (int i = 0; i < size; i++) {
v = vec.get(i);
c = ((Character) v[0]).charValue();
n = ((Integer) v[2]).intValue();
boolean bk = getSuccessor(c, n) != c;
boolean atEnd = (((c == 's') || (c == 'm') || ((c == 'h') && toTime)) && bk);
boolean finishesAtDate = (bk && (c == 'd') && !toTime);
boolean containsEnd = (((StringBuilder) v[1]).toString().indexOf('W') != -1);
if ((!atEnd && !finishesAtDate) || (containsEnd)) {
vecRemovelist.add(v);
}
}
size = vecRemovelist.size();
for (int i = 0; i < size; i++) {
vec.remove(vecRemovelist.get(i));
}
vecRemovelist.clear();
v = vec.get(0); // might throw exception
StringBuilder format = (StringBuilder) v[1];
format.setLength(format.length() - 1);
return format.toString();
}
@SuppressWarnings({"squid:S3776", "squid:S3358"}) // ignore Ternary operators should not be nested
// ignore Cognitive Complexity of methods should not be too high
private final char getSuccessor(char c, int n) {
return ((c == 'y') && (n == 2))
? 'X'
: (((c == 'y') && (n < 4))
? 'y'
: ((c == 'y')
? 'M'
: (((c == 'M') && (n == 2))
? 'Y'
: (((c == 'M') && (n < 3))
? 'M'
: ((c == 'M')
? 'd'
: (((c == 'd') && (n < 2))
? 'd'
: ((c == 'd')
? 'H'
: (((c == 'H') && (n < 2))
? 'H'
: ((c == 'H')
? 'm'
: (((c == 'm') && (n < 2))
? 'm'
: ((c == 'm')
? 's'
: (((c == 's') && (n < 2))
? 's'
: 'W'))))))))))));
}
@SuppressWarnings({
"squid:S3776",
"squid:S6541"
}) // ignore Cognitive Complexity of methods should not be too high
// ignore Methods should not perform too many tasks (aka Brain method)
private void setNumericObject(
int parameterIndex, Object parameterObj, int targetSqlType, int scale) throws SQLException {
Number parameterAsNum;
if (parameterObj instanceof Boolean) {
parameterAsNum =
((Boolean) parameterObj).booleanValue() ? Integer.valueOf(1) : Integer.valueOf(0);
} else if (parameterObj instanceof String) {
switch (targetSqlType) {
case Types.BIT:
if ("1".equals(parameterObj) || "0".equals(parameterObj)) {
parameterAsNum = Integer.valueOf((String) parameterObj);
} else {
boolean parameterAsBoolean = "true".equalsIgnoreCase((String) parameterObj);
parameterAsNum = parameterAsBoolean ? Integer.valueOf(1) : Integer.valueOf(0);
}
break;
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
parameterAsNum = Integer.valueOf((String) parameterObj);
break;
case Types.BIGINT:
parameterAsNum = Long.valueOf((String) parameterObj);
break;
case Types.REAL:
parameterAsNum = Float.valueOf((String) parameterObj);
break;
case Types.FLOAT:
case Types.DOUBLE:
parameterAsNum = Double.valueOf((String) parameterObj);
break;
case Types.DECIMAL:
case Types.NUMERIC:
default:
parameterAsNum = new java.math.BigDecimal((String) parameterObj);
}
} else {
parameterAsNum = (Number) parameterObj;
}
switch (targetSqlType) {
case Types.BIT:
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
setInt(parameterIndex, parameterAsNum.intValue());
break;
case Types.BIGINT:
setLong(parameterIndex, parameterAsNum.longValue());
break;
case Types.REAL:
setFloat(parameterIndex, parameterAsNum.floatValue());
break;
case Types.FLOAT:
setFloat(parameterIndex, parameterAsNum.floatValue());
break;
case Types.DOUBLE:
setDouble(parameterIndex, parameterAsNum.doubleValue());
break;
case Types.DECIMAL:
case Types.NUMERIC:
if (parameterAsNum instanceof java.math.BigDecimal) {
BigDecimal scaledBigDecimal = null;
try {
scaledBigDecimal = ((java.math.BigDecimal) parameterAsNum).setScale(scale);
} catch (ArithmeticException ex) {
try {
scaledBigDecimal =
((java.math.BigDecimal) parameterAsNum).setScale(scale, BigDecimal.ROUND_HALF_UP);
} catch (ArithmeticException arEx) {
throw new SQLException(
"Can't set scale of '"
+ scale
+ "' for DECIMAL argument '"
+ parameterAsNum
+ "'");
}
}
setBigDecimal(parameterIndex, scaledBigDecimal);
} else if (parameterAsNum instanceof java.math.BigInteger) {
setBigDecimal(
parameterIndex,
new java.math.BigDecimal((java.math.BigInteger) parameterAsNum, scale));
} else {
setBigDecimal(parameterIndex, BigDecimal.valueOf(parameterAsNum.doubleValue()));
}
break;
default:
}
}
@Override
public void setRef(int parameterIndex, Ref x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setRowId(int parameterIndex, RowId x) throws SQLException {
throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
}
@Override
public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
}
@Override
public void setShort(int parameterIndex, short x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setString(int parameterIndex, String x) {
// if the sql is insert and the value is not a string literal, add double quotes
if (sql.trim().toUpperCase().startsWith("INSERT") && !x.startsWith("\"") && !x.endsWith("'")) {
this.parameters.put(parameterIndex, "\"" + x + "\"");
} else {
this.parameters.put(parameterIndex, x);
}
}
@Override
public void setTime(int parameterIndex, Time x) throws SQLException {
try {
long time = x.getTime();
String timeprecision = client.getProperties().getTimestampPrecision();
switch (timeprecision.toLowerCase()) {
case "ms":
break;
case "us":
time = time * 1000;
break;
case "ns":
time = time * 1000000;
break;
default:
break;
}
setLong(parameterIndex, time);
} catch (TException e) {
logger.error(
String.format("set time error when iotdb prepared statement :%s ", e.getMessage()));
}
}
@Override
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
try {
ZonedDateTime zonedDateTime = null;
long time = x.getTime();
String timeprecision = client.getProperties().getTimestampPrecision();
switch (timeprecision.toLowerCase()) {
case "ms":
break;
case "us":
time = time * 1000;
break;
case "ns":
time = time * 1000000;
break;
default:
break;
}
if (cal != null) {
zonedDateTime =
ZonedDateTime.ofInstant(
Instant.ofEpochMilli(time), ZoneId.of(cal.getTimeZone().getID()));
} else {
zonedDateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(time), super.zoneId);
}
this.parameters.put(
parameterIndex, zonedDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
} catch (TException e) {
logger.error(
String.format("set time error when iotdb prepared statement :%s ", e.getMessage()));
}
}
@Override
public void setTimestamp(int parameterIndex, Timestamp x) {
ZonedDateTime zonedDateTime =
ZonedDateTime.ofInstant(Instant.ofEpochMilli(x.getTime()), super.zoneId);
this.parameters.put(
parameterIndex, zonedDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}
@Override
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
ZonedDateTime zonedDateTime = null;
if (cal != null) {
zonedDateTime =
ZonedDateTime.ofInstant(
Instant.ofEpochMilli(x.getTime()), ZoneId.of(cal.getTimeZone().getID()));
} else {
zonedDateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(x.getTime()), super.zoneId);
}
this.parameters.put(
parameterIndex, zonedDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}
@Override
public void setURL(int parameterIndex, URL x) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
@Override
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
throw new SQLException(Constant.PARAMETER_SUPPORTED);
}
private String createCompleteSql(final String sql, Map<Integer, String> parameters)
throws SQLException {
List<String> parts = splitSqlStatement(sql);
StringBuilder newSql = new StringBuilder(parts.get(0));
for (int i = 1; i < parts.size(); i++) {
if (logger.isDebugEnabled()) {
logger.debug("SQL {}", sql);
logger.debug("parameters {}", parameters.size());
}
if (!parameters.containsKey(i)) {
throw new SQLException("Parameter #" + i + " is unset");
}
newSql.append(parameters.get(i));
newSql.append(parts.get(i));
}
return newSql.toString();
}
private List<String> splitSqlStatement(final String sql) {
List<String> parts = new ArrayList<>();
int apCount = 0;
int off = 0;
boolean skip = false;
for (int i = 0; i < sql.length(); i++) {
char c = sql.charAt(i);
if (skip) {
skip = false;
continue;
}
switch (c) {
case '\'':
// skip something like 'xxxxx'
apCount++;
break;
case '\\':
// skip something like \r\n
skip = true;
break;
case '?':
// for input like: select a from 'bc' where d, 'bc' will be skipped
if ((apCount & 1) == 0) {
parts.add(sql.substring(off, i));
off = i + 1;
}
break;
default:
break;
}
}
parts.add(sql.substring(off));
return parts;
}
}