Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for Bulkcopy multi byte chars in char/varchar columns #1671

Merged
merged 14 commits into from
Nov 4, 2021
26 changes: 12 additions & 14 deletions src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -4018,8 +4018,7 @@ void writeStream(InputStream inputStream, long advertisedLength,
* efficiency. As this method will only be used in bulk copy, it needs to be efficient. Note: Any changes in
* algorithm/logic should propagate to both writeReader() and writeNonUnicodeReader().
*/
void writeNonUnicodeReader(Reader reader, long advertisedLength, boolean isDestBinary,
Charset charSet) throws SQLServerException {
void writeNonUnicodeReader(Reader reader, long advertisedLength, boolean isDestBinary) throws SQLServerException {
assert DataTypes.UNKNOWN_STREAM_LENGTH == advertisedLength || advertisedLength >= 0;

long actualLength = 0;
Expand Down Expand Up @@ -4057,6 +4056,9 @@ void writeNonUnicodeReader(Reader reader, long advertisedLength, boolean isDestB
// in this last round the only thing that is written is an int value of 0, which is the PLP Terminator
// token(0x00000000).

// collation from database is the collation used
Charset charSet = con.getDatabaseCollation().getCharset();

if (null == charSet) {
writeInt(charsToWrite);

Expand All @@ -4066,20 +4068,16 @@ void writeNonUnicodeReader(Reader reader, long advertisedLength, boolean isDestB

writeBytes(streamByteBuffer, 0, charsToWrite);
} else {
// encoding as per collation
int bytesPerChar = (int) (1 / (Charset.forName(charSet.name()).newDecoder().averageCharsPerByte()));
writeInt(charsToWrite * bytesPerChar);

bytesToWrite = 0;
byte[] charBytes;
for (int charsCopied = 0; charsCopied < charsToWrite; ++charsCopied) {
streamByteBuffer[bytesPerChar * charsCopied] = new String(streamCharBuffer[charsCopied] + "")
.getBytes(charSet)[0];
if (bytesPerChar > 1) {
streamByteBuffer[bytesPerChar * charsCopied
+ 1] = new String(streamCharBuffer[charsCopied] + "").getBytes(charSet)[1];
}
charBytes = new String(streamCharBuffer[charsCopied] + "").getBytes(charSet);
System.arraycopy(charBytes, 0, streamByteBuffer, bytesToWrite, charBytes.length);
bytesToWrite += charBytes.length;
}

writeBytes(streamByteBuffer, 0, bytesPerChar * charsToWrite);
writeInt(bytesToWrite);
writeBytes(streamByteBuffer, 0, bytesToWrite);
}
} else {
bytesToWrite = charsToWrite;
Expand Down Expand Up @@ -4994,7 +4992,7 @@ private void writeInternalTVPRowValues(JDBCType jdbcType, String currentColumnSt
// Null header for v*max types is 0xFFFFFFFFFFFFFFFF.
writeLong(0xFFFFFFFFFFFFFFFFL);
} else if (isSqlVariant) {
// for now we send as bigger type, but is sendStringParameterAsUnicoe is set to false we can't
// for now we send as bigger type, but is sendStringParameterAsUnicode is set to false we can't
// send nvarchar
// since we are writing as nvarchar we need to write as tdstype.bigvarchar value because if we
// want to supprot varchar(8000) it becomes as nvarchar, 8000*2 therefore we should send as
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2270,16 +2270,15 @@ else if (null != sourceCryptoMeta) {
} else {
if ((SSType.BINARY == destSSType) || (SSType.VARBINARY == destSSType)
|| (SSType.VARBINARYMAX == destSSType) || (SSType.IMAGE == destSSType)) {
tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, true,
null);
tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, true);
} else {
SQLCollation destCollation = destColumnMetadata.get(destColOrdinal).collation;
if (null != destCollation) {
tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH,
false, destCollation.getCharset());
false);
} else {
tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH,
false, null);
false);
lilgreenbird marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ private void validateMapping(String sourceType, String destType,
sourceStmt.executeUpdate("CREATE TABLE " + sourceTable + " (col " + sourceType + ");");
sourceStmt.executeUpdate("INSERT INTO " + sourceTable + " VALUES('" + data + "');");

destStmt.executeUpdate("CREATE TABLE " + destTable + " (col NCHAR(5));");
destStmt.executeUpdate("CREATE TABLE " + destTable + " (col CHAR(10));");
lilgreenbird marked this conversation as resolved.
Show resolved Hide resolved
ResultSet sourceRs = sourceStmt.executeQuery("SELECT * FROM " + sourceTable);
bulkCopy.writeToServer(sourceRs);

Expand Down