Hello @jdbi Team :)
This change changes ParsedSql
constructor visibility from private to protected.
Why did I change this? Let me briefly describe.
We recently migrated from JDBI v2 to v3 and we are really astonished of the number of enhancements, but while migrating the code I encountered small blocker.
In our solution I use SqlParser
to process SQL queries from annotated SQL objects. This processing consist of some cheap operations (e.g. prepend DAO name at the query beginning) and some pretty expensive operations (i.e. parse whole SQL and rewrite schemas found in query). Due to expensive nature of SQL parsing resultant SQL should be cached.
What I would like to do is to cache intermediate SQL together with named parameters, e.g. have cache like this one:
intermediateSql = "select a, b, c from {SCHEMA}.test where a > :a", parameters = [ a ]
intermediateSql = "insert into {SCHEMA}.test (a) values (:a)", parameters = [ a ]
And have custom implementation of ParsedSql which can be created by:
public class MyParser implements SqlParser {
public ParsedSql parse(String sql, StatementContext ctx) {
Item item = cache.computeIfAbsent(sql, s -> doExpensiveSqlParsing(s, ctx));
String intermediateSql = item.intermediateSql;
ParsedParameters parameters = item.parameters;
String finalSql = replaceAll("{SCHEMA}", schema);
return new ParsedSql(finalSql, parameters);
}
Since constructor is private and because ParsedSql
can be created only via ParsedSql.Builder
which takes SQL in parts, the ParsedSql
instance cannot be instantiated from fully rendered SQL and known parameters. I have to split it into parts and merge using parameters one-by-one. This is problematic because it makes ?
a magic string which cannot be used in queries (because it's used to split it).
With current solution I can only accept ?
being magic or cache ParsedSql
objects per schema which cause the number of items in cache to raise because there is no limit for a number of applications (and thus the number of schemas located on DB server, due to multitenant environment where application databases are isolated from each other). This will cause cache to grow bigger together with a number of applications, e.g.:
select a, b, c from app0001.test where a > :a; names = [ a ]
select a, b, c from app0002.test where a > :a; names = [ a ]
select a, b, c from app0003.test where a > :a; names = [ a ]
select a, b, c from app0004.test where a > :a; names = [ a ]
insert into app0001.test (a, b, c) values (:a, :b, :c); names = [a, b, c]
insert into app0002.test (a, b, c) values (:a, :b, :c); names = [a, b, c]
insert into app0003.test (a, b, c) values (:a, :b, :c); names = [a, b, c]
insert into app0004.test (a, b, c) values (:a, :b, :c); names = [a, b, c]
etc...
Please let me know if this change (private to protected) is acceptable. The other option for me would be to have Builder
more fluent so I can set both SQL and parameters at once, not in parts, e.g.:
ParsedSql sql = ParsedSql.builder()
.setSql(finalSql)
.setParameters(parameterNames)
.build();
feature