package nl.topicus.jdbc.statement; import java.sql.Types; import javax.xml.bind.DatatypeConverter; import com.google.rpc.Code; import net.sf.jsqlparser.expression.DateValue; import net.sf.jsqlparser.expression.DoubleValue; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; import net.sf.jsqlparser.expression.HexValue; import net.sf.jsqlparser.expression.JdbcParameter; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.NullValue; import net.sf.jsqlparser.expression.SignedExpression; import net.sf.jsqlparser.expression.StringValue; import net.sf.jsqlparser.expression.TimeKeyExpression; import net.sf.jsqlparser.expression.TimeValue; import net.sf.jsqlparser.expression.TimestampValue; import net.sf.jsqlparser.schema.Column; import nl.topicus.jdbc.exception.CloudSpannerSQLException; abstract class AbstractSpannerExpressionVisitorAdapter extends ExpressionVisitorAdapter { private ParameterStore parameterStore; private String column; AbstractSpannerExpressionVisitorAdapter(ParameterStore parameterStore) { this(parameterStore, null); } AbstractSpannerExpressionVisitorAdapter(ParameterStore parameterStore, String column) { this.parameterStore = parameterStore; this.column = column; } protected abstract void setValue(Object value, Integer sqlType); @Override public void visit(JdbcParameter parameter) { Object value = parameterStore.getParameter(parameter.getIndex()); parameterStore.setColumn(parameter.getIndex(), column); setValue(value, parameterStore.getType(parameter.getIndex())); } @Override public void visit(NullValue value) { setValue(null, null); } @Override public void visit(DoubleValue value) { setValue(value.getValue(), Types.DOUBLE); } @Override public void visit(SignedExpression value) { Expression underlyingValue = value.getExpression(); if (underlyingValue instanceof DoubleValue) { DoubleValue doubleValue = (DoubleValue) underlyingValue; doubleValue .setValue(value.getSign() == '-' ? -doubleValue.getValue() : doubleValue.getValue()); visit(doubleValue); } else if (underlyingValue instanceof LongValue) { LongValue longValue = (LongValue) underlyingValue; longValue.setValue(value.getSign() == '-' ? -longValue.getValue() : longValue.getValue()); visit(longValue); } else { super.visit(value); } } @Override public void visit(LongValue value) { setValue(value.getValue(), Types.BIGINT); } @Override public void visit(DateValue value) { setValue(value.getValue(), Types.DATE); } @Override public void visit(TimeValue value) { setValue(value.getValue(), Types.TIME); } @Override public void visit(TimestampValue value) { setValue(value.getValue(), Types.TIMESTAMP); } @Override public void visit(StringValue value) { setValue(value.getValue(), Types.NVARCHAR); } @Override public void visit(HexValue value) { String stringValue = value.getValue().substring(2); byte[] byteValue = DatatypeConverter.parseHexBinary(stringValue); setValue(byteValue, Types.BINARY); } /** * Booleans are not recognized by the parser, but are seen as column names. * * @param column */ @Override public void visit(Column column) { String stringValue = column.getColumnName(); if (stringValue.equalsIgnoreCase("true") || stringValue.equalsIgnoreCase("false")) { setValue(Boolean.valueOf(stringValue), Types.BOOLEAN); } } @Override public void visit(TimeKeyExpression timeKeyExpression) { throw new IllegalArgumentException(new CloudSpannerSQLException( "Function calls such as for example GET_TIMESTAMP() are not allowed in client side insert/update statements. Use an insert statement with a select statement instead: INSERT INTO COL1, COL2, COL3 SELECT 1, GET_TIMESTAMP(), 'test'", Code.INVALID_ARGUMENT)); } }