Environment
-
Metabase version: 0.63.2.7 (self-hosted, JAR on Windows Server 2022)
-
PostgreSQL version: 17
-
JDBC driver: bundled with Metabase
Description
When using the concat() expression in the query builder with string literals as separators, Metabase generates SQL with untyped prepared statement parameters ($9, $10, etc.) that PostgreSQL cannot resolve. This causes the following error in the PostgreSQL log:
ERROR: could not determine data type of parameter $9
Example expression that causes the error:
concat([Created Year], "-", [Created Tertial])
Generated SQL (from PostgreSQL log):
sql
CONCAT(CAST(extract(year FROM "created_col4") AS integer), $9,
CASE WHEN get_month("created_col4") <= 4 THEN $10
WHEN get_month("created_col4") <= 8 THEN $11
ELSE $12 END)
The string literals "-", "T1", "T2", "T3" are sent as untyped parameters. PostgreSQL cannot infer their type when using prepared statements.
The error also occurs with more complex expressions like:
concat("/", [Category 1], "/", [Category 2], "/", [Category 3])
where the "/" separators become $9, $11, $13 etc.
Impact
We have 10 models and 2 questions affected. All cards depending on these models (553+ cards) fail intermittently. Several wallboard dashboards auto-refresh every 30 seconds and generate this error continuously, filling the PostgreSQL log.
What we tried
-
Wrapping first argument with
text():concat(text([Created Year]), "-", [Created Tertial])Result: First argument getsCAST(... AS TEXT)but separator"-"is still untyped as$114. -
Nesting concat to force type inference:
concat(text([Created Year]), concat("-", [Created Tertial]))Result: Separator is still the first argument in the innerCONCATand remains untyped. -
Setting
prepareThreshold=0in additional-options: Saved correctly inmetabase_database.details, Metabase restarted. Result: No effect – prepared statements still used. -
Setting
prepareThreshold=0&preferQueryMode=simple: Result: Metabase sent queries using?placeholders (MySQL syntax) instead of$N, causing a new PostgreSQL error:syntax error at or near "WHEN". Rolled back. -
Setting
prepareThreshold=0&preparedStatementCacheQueries=0: Not yet tested. -
Direct JSON update of
dataset_queryin the application database to restructure expressions – same result as UI changes. -
ALTER ROLE ... SET plan_cache_mode = 'force_generic_plan'on the PostgreSQL server – not possible, no server admin access.