JDBC Call
@JdbcCall defines a JDBC method that executes callable text with a
CallableStatement.
The generated method obtains a connection,
creates the statement with Connection.prepareCall(...),
registers output parameters,
binds inputs,
executes the call,
and reads the declared outputs.
@JdbcCall is intended for portable scalar input, output, and input/output
parameters.
For cursors, result sets, named database types, or a database-specific
multiple-result contract, use @JdbcNative.
❗️Callable statements
Callable text and placeholders
Section titled “Callable text and placeholders”The @JdbcCall value must not be blank.
It is passed to Connection.prepareCall(...) after the processor replaces its
recognised named markers with JDBC parameter markers.
The callable text, its escape syntax, and its compatibility with the selected
database and JDBC driver are application-owned.
Callable text supports only scalar named markers of the form :name.
Each marker must match exactly one Java method parameter, one output derived from
the return type, or both.
@JdbcCall("{ CALL adjust_total(:customerId, :amount, :total) }")@JdbcName("total")BigDecimal adjustTotal(long customerId, BigDecimal amount);An input and an output with the same name define one INOUT position.
An input-only marker defines an IN position.
An output-only marker defines an OUT position.
Unnamed ? markers and expansion markers are not supported for callable text:
?:param.*:param.{values}:param.{names}
The existing SQL tokenizer remains authoritative. Colon text that it does not recognise is passed through unchanged.
Output parameters and return types
Section titled “Output parameters and return types”The return type declares the outputs:
voiddeclares no outputs- a return mapped by a column converter declares one output; its name is the
method-level
@JdbcName - a record mapped from its components declares one output per record component; the component name is the marker name
Every output must occur exactly once in the callable text.
For a column return, @JdbcName is required and must not be blank.
Records and classes handled as single column values follow this rule as well.
A component-mapped record models the completed call and is never null.
Therefore @Nullable and Optional<Record> are invalid for such a record itself.
Individual record components may still use @Nullable or Optional<T> to
represent a SQL NULL output.
record Totals(BigDecimal subtotal, BigDecimal tax) {}
@JdbcCall("{ CALL calculate_totals(:customerId, :subtotal, :tax) }")Totals calculateTotals(long customerId);Output conversion and nullness
Section titled “Output conversion and nullness”An output is read with the getter selected by the JDBC-to-Java column converter.
For one output, converter lookup uses the method return type and an optional
@JdbcConverterName on the method.
For multiple outputs, lookup uses each record component type and an optional
@JdbcConverterName on that component.
Each callable output must use a column converter with an SQL type that does
not require a ResultSet.
A record return is supported when every record component can be mapped
independently by such a column converter.
Converters that read directly from a ResultSet are not applicable to
callable outputs.
Converter discovery and names follow
Converter Lookup.
The SQL type and getter mapping are documented with
JDBC-to-Java converters.
SQL NULL follows the selected Java output type:
Optional<T>receivesOptional.empty()@Nullable Treceivesnull- a primitive output fails with
NullPointerException
Statement configuration
Section titled “Statement configuration”@JdbcQueryTimeout is the only statement configuration supported by generated
callable methods.
It is applied with CallableStatement.setQueryTimeout(...) before execution.
Other statement configuration annotations are unused on an @JdbcCall method
and produce the normal unused-annotation diagnostic.
Generated-code and driver boundary
Section titled “Generated-code and driver boundary”Generated callable code is JDBC-driver-independent.
It does not branch on the database product or generate database-specific JDBC
code.
Required driver settings belong to the application’s DataSource.
For PostgreSQL procedure escape syntax, configure the PostgreSQL JDBC driver
with escapeSyntaxCallMode=callIfNoReturn.
For example:
jdbc:postgresql://localhost:5432/app?escapeSyntaxCallMode=callIfNoReturnGenerated code reads declared output parameters directly after execute().
It does not call getResultSet(), getMoreResults(), or getUpdateCount(),
so it never silently consumes result sets or update counts.
Calls that need such results must use
@JdbcNative and handle their
driver-specific result contract explicitly.
H2 supports the generated input-only and scalar function-return forms used by
the specification tests.
Its Java aliases cannot represent the generated OUT, INOUT, or multiple
output forms; those are verified against the other configured databases.
Error handling
Section titled “Error handling”Invalid callable declarations follow the
processor-wide error contract.
When an error is limited to one callable method, the generated method throws
CodeGenerationException when it is invoked.
Generated SQLException failures are wrapped in JdbcException.