Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Exclude declared generated key columns from SimpleJdbcInsert#37014

Open
junhyeong9812 wants to merge 1 commit into
spring-projects:mainfrom
junhyeong9812:fix/simplejdbcinsert-generated-key-mismatch
Open

Exclude declared generated key columns from SimpleJdbcInsert#37014
junhyeong9812 wants to merge 1 commit into
spring-projects:mainfrom
junhyeong9812:fix/simplejdbcinsert-generated-key-mismatch

Conversation

@junhyeong9812

Copy link
Copy Markdown
Contributor

Overview

TableMetaDataContext.reconcileColumnsToUse() excludes generated key columns from the auto-discovered column list, but when columns are declared explicitly via SimpleJdbcInsert.usingColumns(...), a column also declared via usingGeneratedKeyColumns(...) was not excluded from that declared list. This leaves the generated insert SQL out of sync with the values/types arrays bound to it, causing a parameter count mismatch at execution time whenever a column is declared both ways.

Problem

usingColumns("id", "name") combined with usingGeneratedKeyColumns("id"):

protected List<String> reconcileColumnsToUse(List<String> declaredColumns, String[] generatedKeyNames) {
    if (generatedKeyNames.length > 0) {
        this.generatedKeyColumnsUsed = true;
    }
    if (!declaredColumns.isEmpty()) {
        return new ArrayList<>(declaredColumns);
    }
    ...
}

returns ["id", "name"] unfiltered when declaredColumns is non-empty, while the auto-discovery branch below it already filters out generated key names. createInsertString() independently filters generatedKeyNames when building the SQL, so the insert statement only gets a placeholder for name:

INSERT INTO customers (name) VALUES(?)

but matchInParameterValuesWithInsertColumns(...) and createInsertTypes() both iterate the unfiltered tableColumns (= the declared columns, size 2), producing values/types arrays of size 2. The placeholder count (1) and the bound value count (2) diverge, and the JDBC driver rejects execution with a parameter index error.

Fix

Apply the same generated-key filter to the declared-columns branch that the auto-discovery branch already uses:

protected List<String> reconcileColumnsToUse(List<String> declaredColumns, String[] generatedKeyNames) {
    if (generatedKeyNames.length > 0) {
        this.generatedKeyColumnsUsed = true;
    }
    Set<String> keys = CollectionUtils.newLinkedHashSet(generatedKeyNames.length);
    for (String key : generatedKeyNames) {
        keys.add(key.toUpperCase(Locale.ROOT));
    }
    if (!declaredColumns.isEmpty()) {
        List<String> columns = new ArrayList<>();
        for (String column : declaredColumns) {
            if (!keys.contains(column.toUpperCase(Locale.ROOT))) {
                columns.add(column);
            }
        }
        return columns;
    }
    ...
}

This makes tableColumns — the single source consumed by createInsertString(), createInsertTypes(), and matchInParameterValuesWithInsertColumns(...) — consistently exclude generated key columns regardless of whether they came from auto-discovery or an explicit usingColumns(...) declaration. Added regression tests covering the partial-overlap, full-overlap (declared columns consist entirely of generated keys), and case-insensitive overlap cases.

Note on impact

This changes behavior for the specific combination of declaring a column via both usingColumns(...) and usingGeneratedKeyColumns(...) — previously that combination always failed at execution time, so no working code should depend on the old behavior. That said, it is a behavior change to a protected extension point (reconcileColumnsToUse), so I want to flag it explicitly in case there's a reason to prefer a different approach (e.g. rejecting the overlap explicitly instead of silently excluding it) — happy to adjust if so.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 7, 2026
TableMetaDataContext.reconcileColumnsToUse() filtered generated key
columns out of the auto-discovered column list, but returned declared
columns verbatim when usingColumns() was used together with
usingGeneratedKeyColumns() for the same column. This left the insert
SQL (which filters generated keys separately in createInsertString())
out of sync with the bound values and types arrays (which iterate the
unfiltered declared column list), causing a parameter count mismatch
at execution time.

Signed-off-by: junhyeong9812 <[email protected]>
@junhyeong9812 junhyeong9812 force-pushed the fix/simplejdbcinsert-generated-key-mismatch branch from f47278b to 15d9e57 Compare July 7, 2026 23:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged or decided on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants