Skip to main content

6.2.5 Parameter options

Use #{expression, option=value} to configure one binding. Separate options with commas. Option names, JDBC type names and mode values are case-insensitive; handler names are fully qualified Java class names. Option values are unquoted.

WHERE created_at >= #{since, jdbcType=TIMESTAMP}

These options apply to one placeholder. See SQL hints for connection selection, timeouts and pagination.

Options​

OptionValuePurpose
jdbcTypeJDBC name or integer codeDatabase type, such as VARCHAR, TIMESTAMP, 12
typeHandlerFully qualified handler classConversion for this parameter
modeIN, OUT, INOUT, CURSORDirection; defaults to input
nameOutput nameKey used in the output object
typeNameDatabase type nameNamed type passed to JDBC output registration
scaleIntegerScale for numeric output registration

Handlers are selected from actual DataQL values. The SQL executor has no javaType, entity mapping or rowMapper parameter options.

jdbcType​

A date input can be text or epoch milliseconds. Select its handler with jdbcType:

var read = @@selectSql(value)<%
SELECT CAST(#{value, jdbcType=DATE} AS DATE)
%>;
return read('2026-10-05');

The handler uses JDBC date binding; DataQL receives epoch milliseconds. Common types include VARCHAR, INTEGER (also INT), BIGINT, DECIMAL, DATE, TIME, TIMESTAMP, BLOB, and ARRAY. jdbcType=VARCHAR and jdbcType=12 are equivalent.

Specify a type when writing null:

var clear = @@updateSql(id, name)<%
UPDATE people SET name = #{name, jdbcType=VARCHAR} WHERE id = #{id}
%>;
return clear(1, null);

This assigns SQL NULL and returns an update count of 1.

typeHandler​

This H2 example serializes a DataQL object to JSON text:

var encode = @@selectSql(document)<%
SELECT CAST(#{document,
jdbcType=VARCHAR,
typeHandler=net.hasor.dataql.sqlproc.types.json.JsonTypeHandler} AS VARCHAR)
%>;
return encode({'name':'Alice','tags':['java','dataql']});

It returns the JSON string {"name":"Alice","tags":["java","dataql"]}. An explicit handler takes precedence for this binding, but does not change result-column conversion. Configure a corresponding result mapping to read an object; see SQL type handlers.

The class must be on the application classpath. A public no-argument constructor supports class-name creation. Loading or construction failures fail the SQL call.

mode and name​

callSql and callXml require a driver supporting stored procedures. Assume the database provides add_one(IN input_value INT, OUT output_value INT) and increments its input:

hint bindOut = 'answer';
var calculate = @@callSql(value)<%
{call add_one(
#{value, mode=IN, jdbcType=INTEGER},
#{output, mode=OUT, jdbcType=INTEGER, name=answer}
)}
%>;
return calculate(41);

The expected result is {"answer":42}. OUT does not read an input value, so output needs no fragment argument. name assigns the output key, and bindOut selects outputs to return. Without name, the expression name is used.

INOUT takes an initial value:

hint bindOut = 'answer';
var calculate = @@callSql(value)<%
{call increment_value(#{value, mode=INOUT, jdbcType=INTEGER, name=answer})}
%>;
return calculate(41);

This requires an existing increment_value(INOUT value INT) procedure. Non-cursor output parameters need jdbcType. See stored procedures for a database procedure definition and multiple results.

typeName and scale​

Use a database type name for named output types or a scale for numeric outputs:

#{total, mode=OUT, jdbcType=DECIMAL, scale=2}
#{value, mode=OUT, jdbcType=STRUCT, typeName=APP.ADDRESS_TYPE}

These configure JDBC output registration. When both are present, typeName takes precedence over scale; without either, registration uses only jdbcType. Database-specific objects still require a matching read handler.

CURSOR​

Assume Oracle provides find_people, accepting a minimum age and returning a SYS_REFCURSOR:

hint bindOut = 'rows';
hint FRAGMENT_SQL_OPEN_PACKAGE = 'off';
hint FRAGMENT_SQL_COLUMN_CASE = 'lower';
var find = @@callSql(minAge)<%
{call find_people(#{minAge}, #{rows, mode=CURSOR})}
%>;
return find(25);

The executor registers the cursor for the driver and reads it as a query result. off preserves the row list, producing {"rows":[...]}. This requires a database supporting cursor outputs; the H2 example environment cannot validate Oracle procedures.

ARG rule​

@{arg, , expression, options} and #{expression, options} both create one binding:

WHERE age >= @{arg, , minAge, jdbcType=INTEGER}

Keep the empty position after the rule name; the expression and options belong to the rule body. This generates WHERE age >= ?. The braced parameter form is sufficient for ordinary use.