Skip to content

NamedParameterJdbcOperations batchUpdate: column index is out of range #34153

@koalaa13

Description

@koalaa13

I'm using the latest Spring boot 3.4.1.
How to reproduce bug:

  1. Create table in database:
   @PostConstruct
   public void createTable() {
       final String sql = "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name VARCHAR(255), company " +
               "VARCHAR(255))";
       jdbcTemplate.execute(sql);
   }
  1. Use NamedParameterJdbcOperations for bulk update with this kinda query:
    public void incorrectBulkUpdate(Map<String, List<String>> info) {
        final String sql = "UPDATE users SET company = :company WHERE name IN (:names)";
        SqlParameterSource[] params = info.entrySet().stream()
                .sorted((e1, e2) -> Integer.compare(e1.getValue().size(), e2.getValue().size())) // pay attention to this line!!!
                .map(e -> new MapSqlParameterSource()
                        .addValue("company", e.getKey())
                        .addValue("names", e.getValue())
                )
                .toArray(SqlParameterSource[]::new);
        jdbcOperations.batchUpdate(sql, params);
    }

In general I want to use bulk update with one of query arguments is a collection (in this example argument :names is a list).
Also I sorted parameters with increasing size order of :names argument.
3) Try to execute it with different sized :names argument, for example:


	@Transactional
	@Test
	void incorrectBulkUpdateTest() {
		simpleService.add("John", "google");
		simpleService.add("Nick", "facebook");
		simpleService.add("Anna", "netflix");

		var found = simpleService.findByName("John");

		assertEquals(1, found.size());
		assertEquals("google", found.get(0).company);

		simpleService.incorrectBulkUpdate(
				Map.of(
						"amazon", List.of("Nick", "Anna"),
						"tesla", List.of("John")
				)
		);

		found = simpleService.findByName("John");

		assertEquals(1, found.size());
		assertEquals("tesla", found.get(0).company);
	}

And got something like:

org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [UPDATE users SET company = ? WHERE name IN (?)]; The column index is out of range: 3, number of columns: 2.

But there is a twist.
If I sort arguments in decreasing order, like

.sorted((e1, e2) -> -Integer.compare(e1.getValue().size(), e2.getValue().size()))

everything is fine and test is successful.
I think there is some bug in SQL processing, when query with named parameters is transformed into a query with question marks.

You can see full example in repo: https://github.com/koalaa13/SpringBootIssueExample

Thank you in advance!

Metadata

Metadata

Assignees

No one assigned

    Labels

    in: dataIssues in data modules (jdbc, orm, oxm, tx)status: invalidAn issue that we don't feel is valid

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions