com.mysql.cj.ClientPreparedQueryBindings 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 all versions of mysql-connector-java
JDBC Type 4 driver for MySQL
/*
* Copyright (c) 2017, 2021, 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;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.Duration;
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.temporal.ChronoField;
import java.util.Calendar;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.exceptions.ExceptionFactory;
import com.mysql.cj.exceptions.MysqlErrorNumbers;
import com.mysql.cj.exceptions.WrongArgumentException;
import com.mysql.cj.util.StringUtils;
import com.mysql.cj.util.TimeUtil;
import com.mysql.cj.util.Util;
public class ClientPreparedQueryBindings extends AbstractQueryBindings {
/** Charset encoder used to escape if needed, such as Yen sign in SJIS */
private CharsetEncoder charsetEncoder;
private SimpleDateFormat ddf;
private SimpleDateFormat tdf;
private SimpleDateFormat tsdf = null;
public ClientPreparedQueryBindings(int parameterCount, Session sess) {
super(parameterCount, sess);
if (((NativeSession) this.session).getServerSession().getCharsetSettings().getRequiresEscapingEncoder()) {
this.charsetEncoder = Charset.forName(this.charEncoding).newEncoder();
}
}
@Override
protected void initBindValues(int parameterCount) {
this.bindValues = new ClientPreparedQueryBindValue[parameterCount];
for (int i = 0; i < parameterCount; i++) {
this.bindValues[i] = new ClientPreparedQueryBindValue();
}
}
@Override
public ClientPreparedQueryBindings clone() {
ClientPreparedQueryBindings newBindings = new ClientPreparedQueryBindings(this.bindValues.length, this.session);
ClientPreparedQueryBindValue[] bvs = new ClientPreparedQueryBindValue[this.bindValues.length];
for (int i = 0; i < this.bindValues.length; i++) {
bvs[i] = this.bindValues[i].clone();
}
newBindings.setBindValues(bvs);
newBindings.isLoadDataQuery = this.isLoadDataQuery;
return newBindings;
}
@Override
public void checkParameterSet(int columnIndex) {
if (!this.bindValues[columnIndex].isSet()) {
throw ExceptionFactory.createException(Messages.getString("PreparedStatement.40") + (columnIndex + 1),
MysqlErrorNumbers.SQL_STATE_WRONG_NO_OF_PARAMETERS, 0, true, null, this.session.getExceptionInterceptor());
}
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x) {
setAsciiStream(parameterIndex, x, -1);
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, int length) {
if (x == null) {
setNull(parameterIndex);
} else {
setBinaryStream(parameterIndex, x, length);
}
}
@Override
public void setAsciiStream(int parameterIndex, InputStream x, long length) {
setAsciiStream(parameterIndex, x, (int) length);
this.bindValues[parameterIndex].setMysqlType(MysqlType.TEXT); // TODO was Types.CLOB, check; use length to find right TEXT type
}
@Override
public void setBigDecimal(int parameterIndex, BigDecimal x) {
if (x == null) {
setNull(parameterIndex);
} else {
setValue(parameterIndex, StringUtils.fixDecimalExponent(x.toPlainString()), MysqlType.DECIMAL);
}
}
@Override
public void setBigInteger(int parameterIndex, BigInteger x) {
setValue(parameterIndex, x.toString(), MysqlType.BIGINT_UNSIGNED);
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x) {
setBinaryStream(parameterIndex, x, -1);
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, int length) {
if (x == null) {
setNull(parameterIndex);
} else {
this.bindValues[parameterIndex].setNull(false);
this.bindValues[parameterIndex].setIsStream(true);
this.bindValues[parameterIndex].setMysqlType(MysqlType.BLOB); // TODO use length to find the right BLOB type
this.bindValues[parameterIndex].setStreamValue(x, length);
}
}
@Override
public void setBinaryStream(int parameterIndex, InputStream x, long length) {
setBinaryStream(parameterIndex, x, (int) length);
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream) {
setBinaryStream(parameterIndex, inputStream);
}
@Override
public void setBlob(int parameterIndex, InputStream inputStream, long length) {
setBinaryStream(parameterIndex, inputStream, (int) length);
}
@Override
public void setBlob(int parameterIndex, Blob x) {
if (x == null) {
setNull(parameterIndex);
} else {
try {
setBinaryStream(parameterIndex, x.getBinaryStream(), x.length());
} catch (Throwable t) {
throw ExceptionFactory.createException(t.getMessage(), t, this.session.getExceptionInterceptor());
}
}
}
@Override
public void setBoolean(int parameterIndex, boolean x) {
setValue(parameterIndex, x ? "1" : "0", MysqlType.BOOLEAN);
}
@Override
public void setByte(int parameterIndex, byte x) {
setValue(parameterIndex, String.valueOf(x), MysqlType.TINYINT);
}
public void setBytes(int parameterIndex, byte[] x) {
setBytes(parameterIndex, x, true, true);
if (x != null) {
this.bindValues[parameterIndex].setMysqlType(MysqlType.BINARY); // TODO VARBINARY ?
}
}
public synchronized void setBytes(int parameterIndex, byte[] x, boolean checkForIntroducer, boolean escapeForMBChars) {
if (x == null) {
setNull(parameterIndex); // setNull(parameterIndex, MysqlType.BINARY);
} else {
if (this.session.getServerSession().isNoBackslashEscapesSet()
|| (escapeForMBChars && this.session.getServerSession().getCharsetSettings().isMultibyteCharset(this.charEncoding))) {
// Send as hex
ByteArrayOutputStream bOut = new ByteArrayOutputStream((x.length * 2) + 3);
bOut.write('x');
bOut.write('\'');
// TODO unify with AbstractQueryBindings.hexEscapeBlock()
for (int i = 0; i < x.length; i++) {
int lowBits = (x[i] & 0xff) / 16;
int highBits = (x[i] & 0xff) % 16;
bOut.write(HEX_DIGITS[lowBits]);
bOut.write(HEX_DIGITS[highBits]);
}
bOut.write('\'');
setValue(parameterIndex, bOut.toByteArray(), MysqlType.BINARY); // TODO VARBINARY ?
// save original value for re-usage by refresher SSPS in updatable result set
setOrigValue(parameterIndex, x);
return;
}
// escape them
int numBytes = x.length;
int pad = 2;
if (checkForIntroducer) {
pad += 7;
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream(numBytes + pad);
if (checkForIntroducer) {
bOut.write('_');
bOut.write('b');
bOut.write('i');
bOut.write('n');
bOut.write('a');
bOut.write('r');
bOut.write('y');
}
bOut.write('\'');
for (int i = 0; i < numBytes; ++i) {
byte b = x[i];
switch (b) {
case 0: /* Must be escaped for 'mysql' */
bOut.write('\\');
bOut.write('0');
break;
case '\n': /* Must be escaped for logs */
bOut.write('\\');
bOut.write('n');
break;
case '\r':
bOut.write('\\');
bOut.write('r');
break;
case '\\':
bOut.write('\\');
bOut.write('\\');
break;
case '\'':
bOut.write('\\');
bOut.write('\'');
break;
case '"': /* Better safe than sorry */
bOut.write('\\');
bOut.write('"');
break;
case '\032': /* This gives problems on Win32 */
bOut.write('\\');
bOut.write('Z');
break;
default:
bOut.write(b);
}
}
bOut.write('\'');
setValue(parameterIndex, bOut.toByteArray(), MysqlType.BINARY); // TODO VARBINARY ?
}
}
@Override
public void setBytesNoEscape(int parameterIndex, byte[] parameterAsBytes) {
byte[] parameterWithQuotes = StringUtils.quoteBytes(parameterAsBytes);
setValue(parameterIndex, parameterWithQuotes, MysqlType.BINARY); // TODO VARBINARY ?
}
@Override
public void setBytesNoEscapeNoQuotes(int parameterIndex, byte[] parameterAsBytes) {
setValue(parameterIndex, parameterAsBytes, MysqlType.BINARY); // TODO VARBINARY ?
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader) {
setCharacterStream(parameterIndex, reader, -1);
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, int length) {
try {
if (reader == null) {
setNull(parameterIndex);
} else {
char[] c = null;
int len = 0;
boolean useLength = this.useStreamLengthsInPrepStmts.getValue();
String forcedEncoding = this.session.getPropertySet().getStringProperty(PropertyKey.clobCharacterEncoding).getStringValue();
if (useLength && (length != -1)) {
c = new char[length];
int numCharsRead = Util.readFully(reader, c, length); // blocks until all read
if (forcedEncoding == null) {
setString(parameterIndex, new String(c, 0, numCharsRead));
} else {
setBytes(parameterIndex, StringUtils.getBytes(new String(c, 0, numCharsRead), forcedEncoding));
}
} else {
c = new char[4096];
StringBuilder buf = new StringBuilder();
while ((len = reader.read(c)) != -1) {
buf.append(c, 0, len);
}
if (forcedEncoding == null) {
setString(parameterIndex, buf.toString());
} else {
setBytes(parameterIndex, StringUtils.getBytes(buf.toString(), forcedEncoding));
}
}
this.bindValues[parameterIndex].setMysqlType(MysqlType.TEXT); // TODO was Types.CLOB
}
} catch (UnsupportedEncodingException uec) {
throw ExceptionFactory.createException(WrongArgumentException.class, uec.toString(), uec, this.session.getExceptionInterceptor());
} catch (IOException ioEx) {
throw ExceptionFactory.createException(ioEx.toString(), ioEx, this.session.getExceptionInterceptor());
}
}
@Override
public void setCharacterStream(int parameterIndex, Reader reader, long length) {
setCharacterStream(parameterIndex, reader, (int) length);
}
@Override
public void setClob(int parameterIndex, Reader reader) {
setCharacterStream(parameterIndex, reader);
}
@Override
public void setClob(int parameterIndex, Reader reader, long length) {
setCharacterStream(parameterIndex, reader, length);
}
@Override
public void setClob(int i, Clob x) {
if (x == null) {
setNull(i);
} else {
try {
String forcedEncoding = this.session.getPropertySet().getStringProperty(PropertyKey.clobCharacterEncoding).getStringValue();
if (forcedEncoding == null) {
setString(i, x.getSubString(1L, (int) x.length()));
} else {
setBytes(i, StringUtils.getBytes(x.getSubString(1L, (int) x.length()), forcedEncoding));
}
this.bindValues[i].setMysqlType(MysqlType.TEXT); // TODO was Types.CLOB
} catch (Throwable t) {
throw ExceptionFactory.createException(t.getMessage(), t);
}
}
}
@Override
public void setDate(int parameterIndex, Date x) {
setDate(parameterIndex, x, null);
}
@Override
public void setDate(int parameterIndex, Date x, Calendar cal) {
if (x == null) {
setNull(parameterIndex);
} else if (cal != null) {
setValue(parameterIndex, TimeUtil.getSimpleDateFormat("''yyyy-MM-dd''", cal).format(x), MysqlType.DATE);
} else {
this.ddf = TimeUtil.getSimpleDateFormat(this.ddf, "''yyyy-MM-dd''", this.session.getServerSession().getDefaultTimeZone());
setValue(parameterIndex, this.ddf.format(x), MysqlType.DATE);
}
}
@Override
public void setDouble(int parameterIndex, double x) {
if (!this.session.getPropertySet().getBooleanProperty(PropertyKey.allowNanAndInf).getValue()
&& (x == Double.POSITIVE_INFINITY || x == Double.NEGATIVE_INFINITY || Double.isNaN(x))) {
throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("PreparedStatement.64", new Object[] { x }),
this.session.getExceptionInterceptor());
}
setValue(parameterIndex, StringUtils.fixDecimalExponent(String.valueOf(x)), MysqlType.DOUBLE);
}
@Override
public void setFloat(int parameterIndex, float x) {
setValue(parameterIndex, StringUtils.fixDecimalExponent(String.valueOf(x)), MysqlType.FLOAT); // TODO check; was Types.FLOAT but should be Types.REAL to map to SQL FLOAT
}
@Override
public void setInt(int parameterIndex, int x) {
setValue(parameterIndex, String.valueOf(x), MysqlType.INT);
}
@Override
public void setLocalDate(int parameterIndex, LocalDate x, MysqlType targetMysqlType) {
setValue(parameterIndex, "'" + x + "'", targetMysqlType);
}
@Override
public void setLocalTime(int parameterIndex, LocalTime x, MysqlType targetMysqlType) {
if (targetMysqlType == MysqlType.DATE) {
setValue(parameterIndex, "'" + DEFAULT_DATE + "'", MysqlType.DATE);
return;
}
if (!this.session.getServerSession().getCapabilities().serverSupportsFracSecs() || !this.sendFractionalSeconds.getValue()) {
if (x.getNano() > 0) {
x = x.withNano(0); // truncate nanoseconds
}
} else {
int fractLen = 6; // max supported length (i.e. microsecond)
if (this.columnDefinition != null && parameterIndex <= this.columnDefinition.getFields().length && parameterIndex >= 0) {
// use the column definition if available
fractLen = this.columnDefinition.getFields()[parameterIndex].getDecimals();
}
x = TimeUtil.adjustNanosPrecision(x, fractLen, !this.session.getServerSession().isServerTruncatesFracSecs());
}
DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("HH:mm:ss").appendFraction(ChronoField.NANO_OF_SECOND, 0, 6, true)
.toFormatter();
switch (targetMysqlType) {
case TIME:
StringBuilder sb = new StringBuilder("'");
sb.append(x.format(formatter));
sb.append("'");
setValue(parameterIndex, sb.toString(), targetMysqlType);
break;
case DATETIME:
case TIMESTAMP:
sb = new StringBuilder("'");
sb.append(DEFAULT_DATE);
sb.append(" ");
sb.append(x.format(formatter));
sb.append("'");
setValue(parameterIndex, sb.toString(), targetMysqlType);
break;
default:
break;
}
}
@Override
public void setDuration(int parameterIndex, Duration x, MysqlType targetMysqlType) {
if (!this.session.getServerSession().getCapabilities().serverSupportsFracSecs() || !this.sendFractionalSeconds.getValue()) {
if (x.getNano() > 0) {
x = x.isNegative() ? x.plusSeconds(1).withNanos(0) : x.withNanos(0); // truncate nanoseconds
}
} else {
int fractLen = 6; // max supported length (i.e. microsecond)
if (this.columnDefinition != null && parameterIndex <= this.columnDefinition.getFields().length && parameterIndex >= 0) {
// use the column definition if available
fractLen = this.columnDefinition.getFields()[parameterIndex].getDecimals();
}
x = TimeUtil.adjustNanosPrecision(x, fractLen, !this.session.getServerSession().isServerTruncatesFracSecs());
}
switch (targetMysqlType) {
case TIME:
StringBuilder sb = new StringBuilder("'");
sb.append(TimeUtil.getDurationString(x));
sb.append("'");
setValue(parameterIndex, sb.toString(), targetMysqlType);
break;
default:
break;
}
}
@Override
public void setLocalDateTime(int parameterIndex, LocalDateTime x, MysqlType targetMysqlType) {
if (targetMysqlType == MysqlType.DATE) {
setValue(parameterIndex, "'" + x.toLocalDate() + "'", MysqlType.DATE);
} else {
int fractLen; // max supported length (i.e. microsecond)
switch (targetMysqlType) {
case CHAR:
case VARCHAR:
case TINYTEXT:
case TEXT:
case MEDIUMTEXT:
case LONGTEXT:
fractLen = 9;
break;
default:
fractLen = 6;
break;
}
if (this.columnDefinition != null && parameterIndex <= this.columnDefinition.getFields().length && parameterIndex >= 0) {
// use the column definition if available
fractLen = this.columnDefinition.getFields()[parameterIndex].getDecimals();
}
if (!this.session.getServerSession().getCapabilities().serverSupportsFracSecs() || !this.sendFractionalSeconds.getValue()) {
if (x.getNano() > 0) {
x = x.withNano(0); // truncate nanoseconds
}
} else {
x = TimeUtil.adjustNanosPrecision(x, fractLen, !this.session.getServerSession().isServerTruncatesFracSecs());
}
switch (targetMysqlType) {
case TIME:
DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("HH:mm:ss")
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 6, true).toFormatter();
StringBuilder sb = new StringBuilder("'");
sb.append(x.toLocalTime().format(formatter));
sb.append("'");
setValue(parameterIndex, sb.toString(), targetMysqlType);
break;
case DATETIME:
case TIMESTAMP:
formatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd HH:mm:ss").appendFraction(ChronoField.NANO_OF_SECOND, 0, 6, true)
.toFormatter();
sb = new StringBuilder("'");
sb.append(x.format(formatter));
sb.append("'");
setValue(parameterIndex, sb.toString(), targetMysqlType);
break;
default:
break;
}
}
}
@Override
public void setLong(int parameterIndex, long x) {
setValue(parameterIndex, String.valueOf(x), MysqlType.BIGINT);
}
@Override
public void setNCharacterStream(int parameterIndex, Reader value) {
setNCharacterStream(parameterIndex, value, -1);
}
@Override
public void setNCharacterStream(int parameterIndex, Reader reader, long length) {
if (reader == null) {
setNull(parameterIndex);
} else {
try {
char[] c = null;
int len = 0;
boolean useLength = this.useStreamLengthsInPrepStmts.getValue();
// Ignore "clobCharacterEncoding" because utf8 should be used this time.
if (useLength && (length != -1)) {
c = new char[(int) length]; // can't take more than Integer.MAX_VALUE
int numCharsRead = Util.readFully(reader, c, (int) length); // blocks until all read
setNString(parameterIndex, new String(c, 0, numCharsRead));
} else {
c = new char[4096];
StringBuilder buf = new StringBuilder();
while ((len = reader.read(c)) != -1) {
buf.append(c, 0, len);
}
setNString(parameterIndex, buf.toString());
}
this.bindValues[parameterIndex].setMysqlType(MysqlType.TEXT); // TODO was Types.NCLOB; use length to find right TEXT type
} catch (Throwable t) {
throw ExceptionFactory.createException(t.getMessage(), t, this.session.getExceptionInterceptor());
}
}
}
@Override
public void setNClob(int parameterIndex, Reader reader) {
setNCharacterStream(parameterIndex, reader);
}
@Override
public void setNClob(int parameterIndex, Reader reader, long length) {
if (reader == null) {
setNull(parameterIndex);
} else {
setNCharacterStream(parameterIndex, reader, length);
}
}
@Override
public void setNClob(int parameterIndex, NClob value) {
if (value == null) {
setNull(parameterIndex);
} else {
try {
setNCharacterStream(parameterIndex, value.getCharacterStream(), value.length());
} catch (Throwable t) {
throw ExceptionFactory.createException(t.getMessage(), t, this.session.getExceptionInterceptor());
}
}
}
@Override
public void setNString(int parameterIndex, String x) {
if (x == null) {
setNull(parameterIndex);
} else {
if (this.charEncoding.equalsIgnoreCase("UTF-8") || this.charEncoding.equalsIgnoreCase("utf8")) {
setString(parameterIndex, x);
return;
}
int stringLength = x.length();
// Ignore sql_mode=NO_BACKSLASH_ESCAPES in current implementation.
// Add introducer _utf8 for NATIONAL CHARACTER
StringBuilder buf = new StringBuilder((int) (x.length() * 1.1 + 4));
buf.append("_utf8");
buf.append('\'');
//
// Note: buf.append(char) is _faster_ than appending in blocks, because the block append requires a System.arraycopy().... go figure...
//
for (int i = 0; i < stringLength; ++i) {
char c = x.charAt(i);
switch (c) {
case 0: /* Must be escaped for 'mysql' */
buf.append('\\');
buf.append('0');
break;
case '\n': /* Must be escaped for logs */
buf.append('\\');
buf.append('n');
break;
case '\r':
buf.append('\\');
buf.append('r');
break;
case '\\':
buf.append('\\');
buf.append('\\');
break;
case '\'':
buf.append('\\');
buf.append('\'');
break;
case '"': /* Better safe than sorry */
if (this.session.getServerSession().useAnsiQuotedIdentifiers()) {
buf.append('\\');
}
buf.append('"');
break;
case '\032': /* This gives problems on Win32 */
buf.append('\\');
buf.append('Z');
break;
default:
buf.append(c);
}
}
buf.append('\'');
byte[] parameterAsBytes = this.isLoadDataQuery ? StringUtils.getBytes(buf.toString()) : StringUtils.getBytes(buf.toString(), "UTF-8");
setValue(parameterIndex, parameterAsBytes, MysqlType.VARCHAR); // TODO was Types.NVARCHAR
}
}
@Override
public synchronized void setNull(int parameterIndex) {
setValue(parameterIndex, "null", MysqlType.NULL);
this.bindValues[parameterIndex].setNull(true);
}
@Override
public void setShort(int parameterIndex, short x) {
setValue(parameterIndex, String.valueOf(x), MysqlType.SMALLINT);
}
@Override
public void setString(int parameterIndex, String x) {
if (x == null) {
setNull(parameterIndex);
} else {
int stringLength = x.length();
if (this.session.getServerSession().isNoBackslashEscapesSet()) {
// Scan for any nasty chars
boolean needsHexEscape = isEscapeNeededForString(x, stringLength);
if (!needsHexEscape) {
StringBuilder quotedString = new StringBuilder(x.length() + 2);
quotedString.append('\'');
quotedString.append(x);
quotedString.append('\'');
byte[] parameterAsBytes = this.isLoadDataQuery ? StringUtils.getBytes(quotedString.toString())
: StringUtils.getBytes(quotedString.toString(), this.charEncoding);
setValue(parameterIndex, parameterAsBytes, MysqlType.VARCHAR);
} else {
byte[] parameterAsBytes = this.isLoadDataQuery ? StringUtils.getBytes(x) : StringUtils.getBytes(x, this.charEncoding);
setBytes(parameterIndex, parameterAsBytes);
}
return;
}
String parameterAsString = x;
boolean needsQuoted = true;
if (this.isLoadDataQuery || isEscapeNeededForString(x, stringLength)) {
needsQuoted = false; // saves an allocation later
StringBuilder buf = new StringBuilder((int) (x.length() * 1.1));
buf.append('\'');
//
// Note: buf.append(char) is _faster_ than appending in blocks, because the block append requires a System.arraycopy().... go figure...
//
for (int i = 0; i < stringLength; ++i) {
char c = x.charAt(i);
switch (c) {
case 0: /* Must be escaped for 'mysql' */
buf.append('\\');
buf.append('0');
break;
case '\n': /* Must be escaped for logs */
buf.append('\\');
buf.append('n');
break;
case '\r':
buf.append('\\');
buf.append('r');
break;
case '\\':
buf.append('\\');
buf.append('\\');
break;
case '\'':
buf.append('\'');
buf.append('\'');
break;
case '"': /* Better safe than sorry */
if (this.session.getServerSession().useAnsiQuotedIdentifiers()) {
buf.append('\\');
}
buf.append('"');
break;
case '\032': /* This gives problems on Win32 */
buf.append('\\');
buf.append('Z');
break;
case '\u00a5':
case '\u20a9':
// escape characters interpreted as backslash by mysql
if (this.charsetEncoder != null) {
CharBuffer cbuf = CharBuffer.allocate(1);
ByteBuffer bbuf = ByteBuffer.allocate(1);
cbuf.put(c);
cbuf.position(0);
this.charsetEncoder.encode(cbuf, bbuf, true);
if (bbuf.get(0) == '\\') {
buf.append('\\');
}
}
buf.append(c);
break;
default:
buf.append(c);
}
}
buf.append('\'');
parameterAsString = buf.toString();
}
byte[] parameterAsBytes = this.isLoadDataQuery ? StringUtils.getBytes(parameterAsString)
: (needsQuoted ? StringUtils.getBytesWrapped(parameterAsString, '\'', '\'', this.charEncoding)
: StringUtils.getBytes(parameterAsString, this.charEncoding));
setValue(parameterIndex, parameterAsBytes, MysqlType.VARCHAR);
}
}
private boolean isEscapeNeededForString(String x, int stringLength) {
boolean needsHexEscape = false;
for (int i = 0; i < stringLength; ++i) {
char c = x.charAt(i);
switch (c) {
case 0: /* Must be escaped for 'mysql' */
case '\n': /* Must be escaped for logs */
case '\r':
case '\\':
case '\'':
case '"': /* Better safe than sorry */
case '\032': /* This gives problems on Win32 */
needsHexEscape = true;
break;
}
if (needsHexEscape) {
break; // no need to scan more
}
}
return needsHexEscape;
}
public void setTime(int parameterIndex, Time x, Calendar cal) {
if (x == null) {
setNull(parameterIndex);
return;
}
String formatStr = this.session.getServerSession().getCapabilities().serverSupportsFracSecs() && this.sendFractionalSeconds.getValue()
&& this.sendFractionalSecondsForTime.getValue() && TimeUtil.hasFractionalSeconds(x) ? "''HH:mm:ss.SSS''" : "''HH:mm:ss''";
if (cal != null) {
setValue(parameterIndex, TimeUtil.getSimpleDateFormat(formatStr, cal).format(x), MysqlType.TIME);
} else {
this.tdf = TimeUtil.getSimpleDateFormat(this.tdf, formatStr, this.session.getServerSession().getDefaultTimeZone());
setValue(parameterIndex, this.tdf.format(x), MysqlType.TIME);
}
}
public void setTime(int parameterIndex, Time x) {
setTime(parameterIndex, x, null);
}
@Override
public void bindTimestamp(int parameterIndex, Timestamp x, Calendar targetCalendar, int fractionalLength, MysqlType targetMysqlType) {
if (fractionalLength < 0) {
// default to 6 fractional positions
fractionalLength = 6;
}
x = TimeUtil.adjustNanosPrecision(x, fractionalLength, !this.session.getServerSession().isServerTruncatesFracSecs());
StringBuffer buf = new StringBuffer();
if (targetCalendar != null) {
buf.append(TimeUtil.getSimpleDateFormat("''yyyy-MM-dd HH:mm:ss", targetCalendar).format(x));
} else {
this.tsdf = TimeUtil.getSimpleDateFormat(this.tsdf, "''yyyy-MM-dd HH:mm:ss",
targetMysqlType == MysqlType.TIMESTAMP && this.preserveInstants.getValue() ? this.session.getServerSession().getSessionTimeZone()
: this.session.getServerSession().getDefaultTimeZone());
buf.append(this.tsdf.format(x));
}
if (this.session.getServerSession().getCapabilities().serverSupportsFracSecs() && x.getNanos() > 0) {
buf.append('.');
buf.append(TimeUtil.formatNanos(x.getNanos(), 6));
}
buf.append('\'');
setValue(parameterIndex, buf.toString(), targetMysqlType);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy