Skip to content

Parameter Binding

Parameter binding maps Java method parameters to named SQL markers. The marker format controls how one Java parameter is represented in SQL. Java-to-JDBC converter lookup is described in converter lookup. Parameter nullness terms are defined in the Nullness Contract.

❗️Marker

Kaumei JDBC uses named SQL markers. Each marker name starts with :, for example :name. JDBC ? markers are not supported.

Every SQL marker must match a Java method parameter name. SQL markers without a matching method parameter are invalid.

The marker format defines how the parameter is bound:

  • :param binds exactly one JDBC value. If the Java parameter is a record, array, or list, it is still bound as one value and needs a matching converter for the whole parameter.
  • :param.{values} expands the Java parameter into multiple JDBC values. Records expand their component values in declaration order. Arrays and lists expand their elements in iteration order.
  • :param.* is equivalent to :param.{values}.
  • :param.{names} expands record component names in declaration order. It is valid only for record parameters.
  • @JdbcName on a record component changes the expanded name used by :param.{names}. Values used as expanded record component names must not be blank and must be valid SQL name fragments.

Without @JdbcName, expanded record component names use the following mapping:

  • _ is inserted before an uppercase letter when the preceding character is a lowercase letter or digit
  • _ is also inserted before the last uppercase letter in an uppercase sequence when the following character is lowercase
  • the complete name is converted to lowercase
  • existing underscores are preserved

For example, createdAt expands as created_at, URLValue as url_value, and version2Name as version2_name. An explicit @JdbcName value is used exactly as written.

Expanded names are inserted into the SQL text because JDBC cannot bind column or table names as parameters. Before a name is inserted, Kaumei JDBC validates it as a simple or qualified SQL name fragment. The value may contain dots between non-empty name parts and database-specific characters such as $. It must not start with a dot, end with a dot, or contain empty dot-separated parts such as foo..bar. Whitespace, quotes, commas, semicolons, brackets, operators, parameter markers, escape characters, control characters, and SQL expressions are not allowed. Quoted identifiers and SQL expressions are not supported in @JdbcName.

When quoted identifiers or SQL expressions are needed, write them explicitly in the SQL annotation and use :param.{values} only for values.

Plain property paths are not supported in parameter binding. Use one of the marker formats listed above. A method parameter must also keep one binding shape within one SQL statement; for example, do not mix :param with :param.{values} for the same parameter.

❗️Converter Names

Named converter lookup is described in converter lookup. For parameter binding, @JdbcConverterName("name") selects a named converter on a method parameter. The named converter is applied to the parameter as a whole and is valid only with the whole-parameter :param marker format. @JdbcConverterName values used for parameter binding must not be blank.

@JdbcConverterName is invalid with :param.{values}, :param.{names}, and :param.*. Record components may still use @JdbcConverterName when their values are expanded with :param.{values}.

❗️JDBC Types ❗️JDBC Additional Types

The following JDBC Java types are mapped by default to the PreparedStatement.set... methods:

  • java.lang.String, java.math.BigDecimal, boolean, byte, short, int, long, float, double, byte[], java.sql.Date, java.sql.Time, java.sql.Timestamp, java.sql.Clob, java.sql.Blob, java.sql.Array, java.sql.Ref, java.net.URL, java.sql.RowId, java.sql.NClob, java.sql.SQLXML
  • java.sql.Struct (via setObject)
  • In addition, the following types are supported by default converters that map to the underlying PreparedStatement method:
    • java.lang.Boolean, java.lang.Byte, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Float, java.lang.Double
    • char, java.lang.Character (via setString)
  • Some JDBC drivers do not support all native JDBC types. Check your driver’s documentation.
❗️Record ❗️Enum

Default converters are considered only after converter lookup does not find a matching converter. For the exact lookup order, see converter lookup.

  • Records with exactly one component can use that component as their JDBC value. The component may itself use another converter, but the resolved conversion chain must end in a JDBC-supported value.
  • Enums can use their enum name as a String JDBC value.
❗️Invalid converters

The developer can define converters to set JDBC values from Java.

  • ❗️Simple A static simple converter converts a value T into a supported JDBC valueR:
    • shape: static R toDB(T value)
    • Parameter and return must be unspecified or non-null.
    • The method must be annotated with @JavaToJdbc
  • ❗️Statement A static JDBC converter sets a value R on a given PreparedStatement:
    • shape: static void toDB(PreparedStatement stmt, int index, T value)
    • The parameter value must be nullable or unspecified.
    • The method must handle null correctly.
    • The method must be annotated with @JavaToJdbc
  • ❗️Object An object method annotated with @JavaToJdbc returns the object value as a JDBC value. The return value must be unspecified or non-null.
❗️Collections

Arrays and lists are expanded only when the SQL uses :param.{values} or :param.*. The :param marker binds the array or list as one JDBC value and needs a matching converter for the whole parameter. Dynamic array and list expansion is supported for @JdbcSelect and normal @JdbcUpdate methods. It is not supported in nested @JdbcUpdate methods used by @JdbcBatchUpdate, because the batch SQL is prepared once for the returned batch object.

For practical parameter examples, see mapping Java parameters to JDBC. The number of generated JDBC placeholders matches the size of the array or list. Empty arrays and empty lists are rejected, because they would produce invalid SQL with an empty placeholder list. One collection expansion is limited by @JdbcConfig.maxCollectionPlaceholders. The total number of JDBC placeholders in one generated method call is limited by @JdbcConfig.maxTotalPlaceholders. Both limits can be configured on the selected @JdbcConfig type. Check your JDBC driver and database documentation for stricter database-specific limits on the maximum size of an IN (...) clause.

Optional<T> is not supported as a JDBC method parameter or as an expanded collection/array element.

  • Nullable collections/arrays are not allowed
  • Nullable collection elements are allowed when the collection element type allows null values
  • Primitive array elements are always non-null values