Issue with Batch Insertion using PreparedStatement in SQL Server
anjagarg opened this issue · 6 comments
Driver version
mssql-jdbc-12.6.2.jre11
SQL Server version
Microsoft SQL Server 2019 (RTM-GDR) (KB5035434) - 15.0.2110.4 (X64) Mar 12 2024 18:25:56 Copyright (C) 2019 Microsoft Corporation Standard Edition (64-bit) on Windows 10 Enterprise 10.0 (Build 22631: )
Client Operating System
Windows 11 Enterprise
JAVA/JVM version
11.0.19
Table schema
CREATE TABLE Issuetest(
[Issuetestsid] varchar NOT NULL,
[Originalsid] varchar NOT NULL,
[Identifier] varchar NULL
) ON [PRIMARY]
GO
Problem description
We are experiencing an issue while executing batch insertion using the preparedStatement.executeBatch() method. The problem is that it is inserting object references instead of actual values for VARCHAR columns.
Expected behavior
Should insert actual values
Actual behavior
Object references are being inserted into the table
Error message/stack trace
No Error.
Any other details that can be helpful
Below are the settings that we did to execute the code
- sendStringParametersAsUnicode=false
- connection.setUseBulkCopyForBatchInsert(true)
- There is no Date type column in the target table. (issue not reproducible with date columns)
Sample Code
private def executeSqlBatch(query: String, records: List[scala.Array[Any]], conn: Connection): Unit = {
var connection = conn
var preparedStatement: PreparedStatement = null
try {
preparedStatement = connection.prepareStatement(query)
records.foreach(record => {
var idx = 0
record.foreach { field =>
idx += 1
preparedStatement.setObject(idx, field)
}
preparedStatement.addBatch()
})
if (records.nonEmpty) {
preparedStatement.executeBatch()
} else {
preparedStatement.execute()
}
if (conn == null && connection != null) {
connection.commit()
}
} catch {
case ex: Exception =>
try {
if (conn == null && connection != null) connection.rollback()
} catch {
case rEx: Exception => logger.error("An exception occurred during rollback:", rEx)
}
throw ex
} finally {
preparedStatement.clearBatch()
preparedStatement.clearParameters()
DbUtils.closeQuietly(preparedStatement)
if (conn == null) {
DbUtils.closeQuietly(connection)
}
}
}
hi @anjagarg
thanks, we'll take a look and get back to you.
Meanwhile, could you please confirm if execute batch insertion is possible for columns of JDBCType DateTime with UseBulkCopyForBatchInsert as true?
hi @anjagarg
I've been having some issues with your repro after converting it to java and fixing I'm still unable to see your issue. I discovered that everything works as it should if I don't use sendStringParametersAsUnicode=false
, if I do use it then I get an error "Received an invalid column length from the bcp client for colid 1.". It seems that it's not able to convert the types. If I specify the JDBC type then it all works ie
for (int i = 0; i < 100; i++) {
pstmt.setObject(1, record[0], JDBCType.NVARCHAR);
pstmt.setObject(2, record[1], JDBCType.NVARCHAR);
pstmt.setObject(3, record[2], JDBCType.NVARCHAR);
pstmt.addBatch();
}
Re using DateTime, it should work are you having trouble with that? You probably need to specify the type in setObject as well
Hi, Thank you for your feedback. For datetime column, I have checked that if the target table has column of type DateTime then it throws below error fall back to the original batch insert logic.
'java.lang.IllegalArgumentException: Data type datetime is not supported in bulk copy against Azure Data Warehouse.'
Below is code snippet from sql driver code in SQLServerPreparedStatement class:
switch (jdbctype) {
case microsoft.sql.Types.MONEY:
case microsoft.sql.Types.SMALLMONEY:
case java.sql.Types.DATE:
case microsoft.sql.Types.DATETIME:
case microsoft.sql.Types.DATETIMEOFFSET:
case microsoft.sql.Types.SMALLDATETIME:
case java.sql.Types.TIME:
typeName = ti.getSSTypeName();
form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupportedDW"));
throw new IllegalArgumentException(form.format(new Object[] {typeName}));
Can you confirm in case DATETIME column exists, will it use Bulk API or not?
hi @anjagarg
yes that is correct, that is a known limitation. This is explicitly checked here.