To protect your databases, Elements Connect avoids pasting dependency values directly into the text of a SQL query. Each value inserted with FreeMarker is sent to the database as a SQL parameter: the database treats it as data, never as SQL.
Without this, a user who can edit an issue could type a value that changes the query, and read tables the query was never meant to access.
As a consequence, values can’t be used to build the query itself, and on PostgreSQL they must be converted to the type of the column they are compared to.
What is concerned
These restrictions apply to connected fields using a Database data source with Use FreeMarker to enable dynamic query logic enabled, in:
-
the Query
-
the Live query
They apply to every value inserted with ${...}, for example:
-
${userInput} -
${issue.customfield_10001},${issue.summary}… -
${currentUser.displayName},${reporter.displayName}… -
${currentCustomfield.ids?join(',')}…
What is not allowed
1. A value used as a column, table or sort order
A value can’t provide a column name, a table name, an alias, or the column of an ORDER BY / GROUP BY.
|
Template |
Result |
|---|---|
|
|
❌ Database error |
|
|
❌ Database error |
|
|
⚠️ Sort order ignored, or database error depending on the database |
What to do: use FreeMarker logic to choose between fixed column names:
ORDER BY <#if issue.customfield_10001 == "date">created_date<#else>name</#if>
2. A value used as an operator or SQL keyword
A value can’t provide an operator (=, >, LIKE…) or a keyword (AND, DESC…).
|
Template |
Result |
|---|---|
|
|
❌ Database error |
What to do: same as above, write the operator in the template and use <#if> to choose it.
3. Turning off escaping in a FreeMarker query
The following are refused in SQL queries:
-
the
?no_escbuilt-in, for example${userInput?no_esc} -
the
<#noautoesc>directive -
changing the output format, for example with
<#outputformat>or<#ftl auto_esc=false>
The query is refused as soon as it is read, and the field shows the error:
Disabling auto-escaping or changing the output format is not allowed in a SQL query (line X, column Y): interpolated values must stay bound as SQL parameters.
What to do: remove these constructs from your query and live query.
4. A value inside a SQL comment
A value inserted inside a comment (-- …, /* … */, or # … on MySQL / MariaDB) is removed from the query. This has no effect on the results, since a comment is not executed.
5. Comparing a value to a non-text column on PostgreSQL
Every value is sent as a text parameter. PostgreSQL does not convert text to other types on its own, so comparing a value to a number, date, timestamp or boolean column fails, with or without quotes around the value.
MySQL / MariaDB, SQL Server and Oracle convert the value automatically and are not affected.
|
Template (PostgreSQL) |
Result |
|---|---|
|
|
❌ operator does not exist: integer = character varying |
|
|
❌ Same error |
|
|
❌ Same error |
|
|
❌ operator does not exist: timestamp without time zone > character varying |
|
|
❌ operator does not exist: date = character varying |
|
|
❌ operator does not exist: boolean = character varying |
|
|
✅ Works |
|
|
✅ Works |
|
|
✅ Works |
What to do: convert the value to the type of the column with CAST(${...} AS <type>), or ${...}::<type>.
For a list, convert each element with <#list> instead of ?join:
WHERE customer_id IN (<#list ids as id>CAST(${id} AS INTEGER)<#sep>,</#list>)
Limitations
?join with a variable or several arguments
?join is supported with one fixed separator only (?join(','), ?join("','")). With a separator stored in a variable, or with several arguments, the whole list is sent as one single value, and the query usually returns nothing.
|
Template |
Result |
|---|---|
|
|
✅ Works (on PostgreSQL, only for a text column, see section 5) |
|
|
⚠️ No result |
|
|
⚠️ No result |
?join inside a directive or a string
Do not use ${...?join(...)} inside a FreeMarker directive or a FreeMarker string. The template then fails with a FreeMarker error.
|
Template |
Result |
|---|---|
|
|
❌ Error: evaluated to null or missing |
|
|
❌ Same error |
|
|
❌ The template does not parse |
What to do: use ?join directly in the query (IN (${ids?join(',')})), and test the list itself in conditions: <#if ids?has_content>.
Empty lists
When the list is empty, IN (${ids?join(',')}) produces IN (), which is invalid SQL. Protect it with a condition:
<#if ids?has_content>WHERE id IN (${ids?join(',')})</#if>
Database-specific quoting
Some database-specific ways of writing strings or names are not recognized when they contain a value: PostgreSQL $$…$$ or E'…' strings, MySQL \' escapes inside a string, SQL Server [...] names. The query may be refused with the error:
Unable to safely parameterize the FreeMarker SQL query (unresolved value placeholder)
or fail on the database side.
What to do: use standard single quotes ('…') around values, and double a quote to escape it ('').