Hendy Irawan opened SPR-13181 and commented
For the following SQL:
UPDATE ppdbbandung2015.school
SET
name=:name,
code=:code,
level=:level,
address=:address,
address_district=:address_district,
address_subdistrict=:address_subdistrict,
address_rw=:address_rw,
address_rt=:address_rt,
is_border=:is_border,
foreigner_percentage=:foreigner_percentage,
option_i=:option_i,
option=ARRAY[:option]::json[]
WHERE id=:id;
Notice that we have ARRAY[:option]
which should be proper when executed in PostgreSQL, however Spring parses the ]
after :option
as part of the parameter name, resulting in:
org.springframework.dao.InvalidDataAccessApiUsageException: No value supplied for the SQL parameter 'option]': No value registered for key 'option]'
at org.springframework.jdbc.core.namedparam.NamedParameterUtils.buildValueArray(NamedParameterUtils.java:336)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.getPreparedStatementCreator(NamedParameterJdbcTemplate.java:374)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:313)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:318)
at org.soluvas.scrape.core.sql.TableDmlGenerator.lambda$upsert$6(TableDmlGenerator.java:128)
at org.soluvas.scrape.core.sql.TableDmlGenerator$$Lambda$3/1563634025.doInTransaction(Unknown Source)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
at org.soluvas.scrape.core.sql.TableDmlGenerator.upsert(TableDmlGenerator.java:108)
at org.soluvas.scrape.core.UpsertTest.upsert(UpsertTest.java:76)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
Workaround: just add a space after the parameter name, however such special characters (e.g. "]", "{" ) should never form part of a named parameter.
Related to #17770, #17771.
Affects: 4.1.7
Comment From: spring-projects-issues
Bulk closing outdated, unresolved issues. Please, reopen if still relevant.
Comment From: foal
Still relevant
Comment From: Chen-Clark
?
Comment From: snicoll
I did a quick test and didn't manage to reproduce this issue. Given that several people here claim it is relevant, please share a small test that reproduces the problem. Tests of NamedParameterUtils
are quite easy to build.
This is the test that I used:
@Test // gh-17773
public void parseSqlStatementWithPostgresArray() {
String sql = """
UPDATE ppdbbandung2015.school
SET
name=:name,
code=:code,
level=:level,
address=:address,
address_district=:address_district
address_subdistrict=:address_subdistrict
address_rw=:address_rw
address_rt=:address_rt
is_border=:is_border,
foreigner_percentage=:foreigner_percentage,
option_i=:option_i,
option=ARRAY[:option]::json[]
WHERE id=:id;""";
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsedSql.getParameterNames()).containsOnly(
"name", "code", "level", "address", "address_district",
"address_subdistrict", "address_rw", "address_rt",
"is_border", "foreigner_percentage", "option_i",
"option", "id");
}
Comment From: sbrannen
This appears to have been fixed in #27716 and #27925.
If you still encounter this issue with Spring Framework 6.0.13 (or a later version), please create a new issue.
Thanks