Skip to content

Query-context parameters

A query-context parameter is a named, typed value that the engine resolves per request from the connection’s session attributes. Unlike a calculated member (fixed at author time) or Looker-style Liquid (arbitrary runtime SQL), a query parameter is bounded and sandboxed: it is typed, optionally restricted to a fixed set of allowed values, and can only be used as a bind value — never interpolated into SQL.

You declare a <QueryParameter> once in the schema, supply its value at connect time via a session.<name> property, and reference it where the engine accepts a bound value — today, in predicate-based row security.

The security model

The no-injection guarantee comes from typing plus enumeration, not from escaping:

  • Every supplied value is coerced to the declared type (String, Numeric, Date, Member) and, when an allowed-value set is declared, checked against itbefore it can ever become part of a query.
  • A value that is the wrong type or outside the allowed set is rejected at connect time (the connection fails loudly), never silently passed through.
  • The validated value reaches SQL only as a bound literal at a single, audited substitution point. There is no free-form templating.

Declaring a parameter

A <QueryParameter> is a top-level schema element (alongside <Role>). Give it a name, a type, an optional defaultValue, and an optional list of <QueryParameterValue> allowed values (the closed enumeration).

<QueryParameter name="region" type="String" defaultValue="EAST">
<QueryParameterValue>EAST</QueryParameterValue>
<QueryParameterValue>WEST</QueryParameterValue>
</QueryParameter>
typeCoerced toNotes
Stringstring
Numericnumber
DateISO date (yyyy-MM-dd)
Membera member’s leaf keySingle-key levels only

If allowed_values is omitted the parameter is unconstrained (still type-checked). A declared default_value must itself be in the allowed set.

Supplying a value at connect time

Values arrive on the connection through session.<name> properties — the same channel Saiku uses to pass user attributes, and the same one dynamic roles read.

Provider=mondrian;Jdbc=...;Catalog=...;session.region=WEST

When the connection is established the engine builds a validated parameter context: each declared parameter takes its session.<name> value if present, otherwise its default; the value is coerced and checked against the allowed set. An illegal value fails the connection rather than producing wrong results.

Using a parameter for row security

The primary use is predicate-based row security: restrict a measure group’s fact rows to those whose real fact column matches the requesting user’s parameter value. Declare a <PredicateGrant> on a role; the Calcite adapter injects it as a WHERE filter on every segment load for that measure group, pre-aggregation, so totals are correctly restricted.

<Role name="Regional">
<SchemaGrant access="all">
<CubeGrant cube="Sales" access="all">
<!-- restrict Sales fact rows to the user's region -->
<PredicateGrant measureGroup="Sales" column="region"
operator="eq" parameter="region"/>
</CubeGrant>
</SchemaGrant>
</Role>

Now two users connecting with session.region=EAST and session.region=WEST see correctly different, non-overlapping totals over the same query — and the predicate appears in the generated SQL on every load of the secured measure group.

Field-switching

A parameter can also select which of a fixed set of pre-declared measures or columns is active — Looker’s parameter field-switching pattern. On the engine side you declare the set; the selection is injected at the query layer as a standard MDX WITH MEMBER / WITH SET that reads the parameter context, so it stays within the bounded, no-templating contract.

Migrating from Looker

A LookML parameter field maps directly to a <QueryParameter> (type + allowed_values + default). A parameter’s use inside {% parameter %} Liquid SQL is the dynamic-templating case the importer still refuses — see Migrating from Looker.