Skip to content

[BUG] PreparedStatement.executeBatch() When the Insert Sql Column Name Case Mismatch, Throws SQLServerException "Unable to retrieve column metadata." #2588

Open
@wooln

Description

@wooln

Driver version

12.8.1

SQL Server version

Microsoft SQL Server 2019 (RTM-CU29) (KB5046365) - 15.0.4405.4 (X64) 
	Oct 23 2024 08:45:19 
	Copyright (C) 2019 Microsoft Corporation
	Developer Edition (64-bit) on Linux (Ubuntu 20.04.6 LTS) <X64>

Client Operating System

openSUSE Leap 15.6 x86_64

JAVA/JVM version

java version 22

Problem description

PreparedStatement.executeBatch(), when the insert sql column name case mismatch, Throws SQLServerException "Unable to retrieve column metadata."

  1. create table, c1 lower case.
    CREATE TABLE varchartable1 (c1 varchar(10))

  2. executeBatch

    Column name use lower case c1, succeed
    con.prepareStatement("INSERT INTO varchartable1 (c1) VALUES(?)")

    Column name use upper case C1, throws SQLServerException "Unable to retrieve column metadata."
    con.prepareStatement("INSERT INTO varchartable1 (C1) VALUES(?)")

The unit tests.

  1. succeed
@Test
public void testExecuteBatchColumnCaseMatching() throws Exception {
    String varcharTable1 = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("varchartable1"));
    // Insert Timestamp using prepared statement when useBulkCopyForBatchInsert=true
    try (Connection con = DriverManager.getConnection(connectionString
            + ";useBulkCopyForBatchInsert=true;sendTemporalDataTypesAsStringForBulkCopy=false;")) {
        try (Statement statement = con.createStatement()) {
            TestUtils.dropTableIfExists(varcharTable1, statement);
            String createSql = "CREATE TABLE" + varcharTable1 + " (c1 varchar(10))";
            statement.execute(createSql);
        }
        try (PreparedStatement preparedStatement = con.prepareStatement("INSERT INTO " + varcharTable1 + "(c1) VALUES(?)")) {
            preparedStatement.setObject(1, "value1");
            preparedStatement.addBatch();
            preparedStatement.setObject(1, "value2");
            preparedStatement.addBatch();
            preparedStatement.executeBatch();
        }
    }
}
  1. throws SQLServerException "Unable to retrieve column metadata."
@Test
public void testExecuteBatchColumnCaseMismatch() throws Exception {
    String varcharTable1 = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("varchartable1"));
    // Insert Timestamp using prepared statement when useBulkCopyForBatchInsert=true
    try (Connection con = DriverManager.getConnection(connectionString
            + ";useBulkCopyForBatchInsert=true;sendTemporalDataTypesAsStringForBulkCopy=false;")) {
        try (Statement statement = con.createStatement()) {
            TestUtils.dropTableIfExists(varcharTable1, statement);
            String createSql = "CREATE TABLE" + varcharTable1 + " (c1 varchar(10))";
            statement.execute(createSql);
        }
        // upper case C1
        try (PreparedStatement preparedStatement = con.prepareStatement("INSERT INTO " + varcharTable1 + "(C1) VALUES(?)")) {
            preparedStatement.setObject(1, "value1");
            preparedStatement.addBatch();
            preparedStatement.setObject(1, "value2");
            preparedStatement.addBatch();
            try {
                preparedStatement.executeBatch();
                fail("Should have failed");
            } catch (Exception ex) {
                assertInstanceOf(SQLServerException.class, ex);
                assertEquals("Unable to retrieve column metadata.", ex.getMessage());
            }
        }
    }
}

Activity

wooln

wooln commented on Feb 1, 2025

@wooln
Author

Database use a case-sensitive (like SQL_Latin1_General_CP1_CS_AS) and a table like this create table [Test1] ([C1] int, [c1] varchar)

I covered the unit tests that use both columns c1 and C1, and an exception occurred, indicating that no one has ever covered CS before.

com.microsoft.sqlserver.jdbc.SQLServerException: Duplicate column names are not allowed.

	at com.microsoft.sqlserver.jdbc.SQLServerBulkRecord.checkDuplicateColumnName(SQLServerBulkRecord.java:157)
	at com.microsoft.sqlserver.jdbc.SQLServerBulkBatchInsertRecord.addColumnMetadataInternal(SQLServerBulkBatchInsertRecord.java:323)
	at com.microsoft.sqlserver.jdbc.SQLServerBulkRecord.addColumnMetadata(SQLServerBulkRecord.java:83)
	at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeBatch(SQLServerPreparedStatement.java:2232)
	at com.microsoft.sqlserver.jdbc.unit.statement.BatchExecutionTest.testExecuteBatchColumnCaseMismatch_CS(BatchExecutionTest.java:632)
moved this from To be triaged to Under Peer Review in MSSQL JDBCon Feb 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

Under Peer Review

Milestone

No milestone

Relationships

None yet

    Participants

    @wooln

    Issue actions

      [BUG] PreparedStatement.executeBatch() When the Insert Sql Column Name Case Mismatch, Throws SQLServerException "Unable to retrieve column metadata." · Issue #2588 · microsoft/mssql-jdbc