com.mysql.cj.protocol.a.AbstractValueEncoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mysql-connector-java Show documentation
Show all versions of mysql-connector-java Show documentation
Fixed bugs repo for official MySQL JDBC connector
The newest version!
/*
* Copyright (c) 2022, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
* Free Software Foundation.
*
* This program is also distributed with certain software (including but not
* limited to OpenSSL) that is licensed under separate terms, as designated in a
* particular file or component or in included license documentation. The
* authors of MySQL hereby grant you an additional permission to link the
* program and your derivative works with the separately licensed software that
* they have included with MySQL.
*
* Without limiting anything contained in the foregoing, this file, which is
* part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
* version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
* for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.mysql.cj.protocol.a;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.concurrent.TimeUnit;
import com.mysql.cj.BindValue;
import com.mysql.cj.Messages;
import com.mysql.cj.MysqlType;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.conf.PropertySet;
import com.mysql.cj.conf.RuntimeProperty;
import com.mysql.cj.exceptions.ExceptionFactory;
import com.mysql.cj.exceptions.ExceptionInterceptor;
import com.mysql.cj.exceptions.WrongArgumentException;
import com.mysql.cj.protocol.InternalDate;
import com.mysql.cj.protocol.InternalTime;
import com.mysql.cj.protocol.InternalTimestamp;
import com.mysql.cj.protocol.Message;
import com.mysql.cj.protocol.ServerSession;
import com.mysql.cj.protocol.ValueEncoder;
import com.mysql.cj.protocol.a.NativeConstants.IntegerDataType;
import com.mysql.cj.protocol.a.NativeConstants.StringLengthDataType;
import com.mysql.cj.protocol.a.NativeConstants.StringSelfDataType;
import com.mysql.cj.result.Field;
import com.mysql.cj.util.StringUtils;
import com.mysql.cj.util.TimeUtil;
public abstract class AbstractValueEncoder implements ValueEncoder {
protected PropertySet propertySet;
protected ServerSession serverSession;
protected ExceptionInterceptor exceptionInterceptor;
protected RuntimeProperty charEncoding = null;
protected RuntimeProperty sendFractionalSeconds;
protected RuntimeProperty sendFractionalSecondsForTime;
protected RuntimeProperty preserveInstants;
@Override
public void init(PropertySet pset, ServerSession serverSess, ExceptionInterceptor excInterceptor) {
this.propertySet = pset;
this.serverSession = serverSess;
this.exceptionInterceptor = excInterceptor;
this.charEncoding = pset.getStringProperty(PropertyKey.characterEncoding);
this.sendFractionalSeconds = pset.getBooleanProperty(PropertyKey.sendFractionalSeconds);
this.sendFractionalSecondsForTime = pset.getBooleanProperty(PropertyKey.sendFractionalSecondsForTime);
this.preserveInstants = pset.getBooleanProperty(PropertyKey.preserveInstants);
}
@Override
public byte[] getBytes(BindValue binding) {
return StringUtils.getBytes(getString(binding), this.charEncoding.getValue());
}
@Override
public void encodeAsText(Message msg, BindValue binding) {
NativePacketPayload intoPacket = (NativePacketPayload) msg;
intoPacket.writeBytes(StringLengthDataType.STRING_FIXED, getBytes(binding));
}
@Override
public void encodeAsQueryAttribute(Message msg, BindValue binding) {
NativePacketPayload intoPacket = (NativePacketPayload) msg;
String x = binding.getValue().toString();
intoPacket.writeBytes(StringSelfDataType.STRING_LENENC, StringUtils.getBytes(x, this.charEncoding.getValue()));
}
protected BigDecimal getScaled(BigDecimal x, long scaleOrLength) {
BigDecimal scaledBigDecimal;
if (scaleOrLength < 0) {
return x.setScale(x.scale());
}
try {
scaledBigDecimal = x.setScale((int) scaleOrLength);
} catch (ArithmeticException ex) {
try {
scaledBigDecimal = x.setScale((int) scaleOrLength, BigDecimal.ROUND_HALF_UP);
} catch (ArithmeticException arEx) {
throw ExceptionFactory.createException(WrongArgumentException.class,
Messages.getString("PreparedStatement.65", new Object[] { scaleOrLength, x.toPlainString() }), this.exceptionInterceptor);
}
}
return scaledBigDecimal;
}
protected LocalTime adjustLocalTime(LocalTime x, Field f) {
if (!this.serverSession.getCapabilities().serverSupportsFracSecs() || !this.sendFractionalSeconds.getValue()) {
if (x.getNano() > 0) {
x = x.withNano(0); // truncate nanoseconds
}
return x;
}
return TimeUtil.adjustNanosPrecision(x, f == null ? 6 : f.getDecimals(), !this.serverSession.isServerTruncatesFracSecs());
}
protected LocalDateTime adjustLocalDateTime(LocalDateTime x, Field f) {
if (!this.serverSession.getCapabilities().serverSupportsFracSecs() || !this.sendFractionalSeconds.getValue()) {
if (x.getNano() > 0) {
x = x.withNano(0); // truncate nanoseconds
}
return x;
}
return TimeUtil.adjustNanosPrecision(x, f == null ? 6 : f.getDecimals(), !this.serverSession.isServerTruncatesFracSecs());
}
protected Duration adjustDuration(Duration x, Field f) {
if (!this.serverSession.getCapabilities().serverSupportsFracSecs() || !this.sendFractionalSeconds.getValue()) {
if (x.getNano() > 0) {
x = x.isNegative() ? x.plusSeconds(1).withNanos(0) : x.withNanos(0); // truncate nanoseconds
}
return x;
}
return TimeUtil.adjustNanosPrecision(x, f == null ? 6 : f.getDecimals(), !this.serverSession.isServerTruncatesFracSecs());
}
protected Timestamp adjustTimestamp(Timestamp x, Field f, boolean keepOrigNanos) {
if (keepOrigNanos) {
return x; // if the value is set as a key for UpdatableResultSet updater, it should keep original milliseconds
}
if (!this.serverSession.getCapabilities().serverSupportsFracSecs() || !this.sendFractionalSeconds.getValue()) {
return TimeUtil.truncateFractionalSeconds(x);
}
return TimeUtil.adjustNanosPrecision(x, f == null ? 6 : f.getDecimals(), !this.serverSession.isServerTruncatesFracSecs());
}
protected Time adjustTime(Time x) {
if (!this.serverSession.getCapabilities().serverSupportsFracSecs() || !this.sendFractionalSeconds.getValue()
|| !this.sendFractionalSecondsForTime.getValue()) {
return TimeUtil.truncateFractionalSeconds(x);
}
return x;
}
protected void writeDate(Message msg, InternalDate d) {
NativePacketPayload intoPacket = (NativePacketPayload) msg;
intoPacket.ensureCapacity(NativeConstants.BIN_LEN_DATE + 1);
intoPacket.writeInteger(IntegerDataType.INT1, NativeConstants.BIN_LEN_DATE);
intoPacket.writeInteger(IntegerDataType.INT2, d.getYear());
intoPacket.writeInteger(IntegerDataType.INT1, d.getMonth());
intoPacket.writeInteger(IntegerDataType.INT1, d.getDay());
}
protected void writeTime(Message msg, InternalTime time) {
NativePacketPayload intoPacket = (NativePacketPayload) msg;
boolean hasFractionalSeconds = time.getNanos() > 0;
intoPacket.ensureCapacity((hasFractionalSeconds ? NativeConstants.BIN_LEN_TIME_WITH_MICROS : NativeConstants.BIN_LEN_TIME_NO_FRAC) + 1);
intoPacket.writeInteger(IntegerDataType.INT1, hasFractionalSeconds ? NativeConstants.BIN_LEN_TIME_WITH_MICROS : NativeConstants.BIN_LEN_TIME_NO_FRAC);
intoPacket.writeInteger(IntegerDataType.INT1, time.isNegative() ? 1 : 0);
intoPacket.writeInteger(IntegerDataType.INT4, time.getHours() / 24);
intoPacket.writeInteger(IntegerDataType.INT1, time.getHours() % 24);
intoPacket.writeInteger(IntegerDataType.INT1, time.getMinutes());
intoPacket.writeInteger(IntegerDataType.INT1, time.getSeconds());
if (hasFractionalSeconds) {
intoPacket.writeInteger(IntegerDataType.INT4, TimeUnit.NANOSECONDS.toMicros(time.getNanos()));
}
}
protected void writeDateTime(Message msg, InternalTimestamp ts) {
NativePacketPayload intoPacket = (NativePacketPayload) msg;
long microseconds = TimeUnit.NANOSECONDS.toMicros(ts.getNanos());
intoPacket.ensureCapacity((microseconds > 0 ? NativeConstants.BIN_LEN_TIMESTAMP_WITH_MICROS : NativeConstants.BIN_LEN_TIMESTAMP_NO_FRAC) + 1);
intoPacket.writeInteger(IntegerDataType.INT1,
microseconds > 0 ? NativeConstants.BIN_LEN_TIMESTAMP_WITH_MICROS : NativeConstants.BIN_LEN_TIMESTAMP_NO_FRAC);
intoPacket.writeInteger(IntegerDataType.INT2, ts.getYear());
intoPacket.writeInteger(IntegerDataType.INT1, ts.getMonth());
intoPacket.writeInteger(IntegerDataType.INT1, ts.getDay());
intoPacket.writeInteger(IntegerDataType.INT1, ts.getHours());
intoPacket.writeInteger(IntegerDataType.INT1, ts.getMinutes());
intoPacket.writeInteger(IntegerDataType.INT1, ts.getSeconds());
if (microseconds > 0) {
intoPacket.writeInteger(IntegerDataType.INT4, microseconds);
}
}
public void writeDateTimeWithOffset(Message msg, InternalTimestamp timestamp) {
NativePacketPayload intoPacket = (NativePacketPayload) msg;
intoPacket.ensureCapacity(NativeConstants.BIN_LEN_TIMESTAMP_WITH_TZ + 1);
intoPacket.writeInteger(IntegerDataType.INT1, NativeConstants.BIN_LEN_TIMESTAMP_WITH_TZ);
intoPacket.writeInteger(IntegerDataType.INT2, timestamp.getYear());
intoPacket.writeInteger(IntegerDataType.INT1, timestamp.getMonth());
intoPacket.writeInteger(IntegerDataType.INT1, timestamp.getDay());
intoPacket.writeInteger(IntegerDataType.INT1, timestamp.getHours());
intoPacket.writeInteger(IntegerDataType.INT1, timestamp.getMinutes());
intoPacket.writeInteger(IntegerDataType.INT1, timestamp.getSeconds());
intoPacket.writeInteger(IntegerDataType.INT4, TimeUnit.NANOSECONDS.toMicros(timestamp.getNanos()));
intoPacket.writeInteger(IntegerDataType.INT2, timestamp.getOffset());
}
protected byte[] escapeBytesIfNeeded(byte[] x) {
if (this.serverSession.isNoBackslashEscapesSet() || this.serverSession.getCharsetSettings().isMultibyteCharset(this.charEncoding.getValue())) {
// Send as hex
ByteArrayOutputStream bOut = new ByteArrayOutputStream((x.length * 2) + 3);
bOut.write('x');
bOut.write('\'');
StringUtils.hexEscapeBlock(x, x.length, (lowBits, highBits) -> {
bOut.write(lowBits);
bOut.write(highBits);
});
bOut.write('\'');
return bOut.toByteArray();
}
// escape them
ByteArrayOutputStream bOut = new ByteArrayOutputStream(x.length + 9);
bOut.write('_');
bOut.write('b');
bOut.write('i');
bOut.write('n');
bOut.write('a');
bOut.write('r');
bOut.write('y');
bOut.write('\'');
StringUtils.escapeBytes(bOut, x);
bOut.write('\'');
return bOut.toByteArray();
}
@Override
public long getTextLength(BindValue binding) {
if (binding.isNull()) {
return 4 /* for NULL literal in SQL */;
}
return binding.isStream() && binding.getScaleOrLength() != -1 ? binding.getScaleOrLength() * 2 /* for safety in escaping */
: binding.getByteValue().length;
}
@Override
public long getBinaryLength(BindValue binding) {
if (binding.isNull()) {
return 0;
}
if (binding.isStream() && binding.getScaleOrLength() != -1) {
return binding.getScaleOrLength();
}
int bufferType = binding.getFieldType();
switch (bufferType) {
case MysqlType.FIELD_TYPE_TINY:
return NativeConstants.BIN_LEN_INT1;
case MysqlType.FIELD_TYPE_SHORT:
return NativeConstants.BIN_LEN_INT2;
case MysqlType.FIELD_TYPE_LONG:
return NativeConstants.BIN_LEN_INT4;
case MysqlType.FIELD_TYPE_LONGLONG:
return NativeConstants.BIN_LEN_INT8;
case MysqlType.FIELD_TYPE_FLOAT:
return NativeConstants.BIN_LEN_FLOAT;
case MysqlType.FIELD_TYPE_DOUBLE:
return NativeConstants.BIN_LEN_DOUBLE;
case MysqlType.FIELD_TYPE_DATE:
return NativeConstants.BIN_LEN_DATE + 1;
case MysqlType.FIELD_TYPE_TIME:
return NativeConstants.BIN_LEN_TIME_WITH_MICROS + 1;
case MysqlType.FIELD_TYPE_DATETIME:
return NativeConstants.BIN_LEN_TIMESTAMP_WITH_MICROS + 1;
case MysqlType.FIELD_TYPE_TIMESTAMP:
return NativeConstants.BIN_LEN_TIMESTAMP_WITH_TZ + 1;
case MysqlType.FIELD_TYPE_VAR_STRING:
return binding.getValue().toString().length() + 9;
case MysqlType.FIELD_TYPE_STRING:
case MysqlType.FIELD_TYPE_VARCHAR:
case MysqlType.FIELD_TYPE_DECIMAL:
case MysqlType.FIELD_TYPE_NEWDECIMAL:
if (binding.getValue() instanceof byte[]) {
return ((byte[]) binding.getValue()).length;
} else if (binding.getValue() instanceof BigDecimal) {
return ((BigDecimal) binding.getValue()).toPlainString().length();
}
return ((String) binding.getValue()).length();
default:
return 0;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy