prestodb/presto · error · SemanticException
EXPRESSION_NOT_CONSTANT
EXPRESSION_NOT_CONSTANT
Error message
Constant expression cannot contain column references
What it means
ConstantExpressionVerifier validates that expressions used where constants are required (e.g. parameter default values, EXPLAIN options) contain no column references. A DereferenceExpression (e.g. t.col) that itself appears in the expression's column-reference set is rejected with EXPRESSION_NOT_CONSTANT.
Source
Thrown at presto-analyzer/src/main/java/com/facebook/presto/sql/analyzer/ConstantExpressionVerifier.java:54
}
private static class ConstantExpressionVerifierVisitor
extends DefaultTraversalVisitor<Void, Void>
{
private final Set<NodeRef<Expression>> columnReferences;
private final Expression expression;
public ConstantExpressionVerifierVisitor(Set<NodeRef<Expression>> columnReferences, Expression expression)
{
this.columnReferences = columnReferences;
this.expression = expression;
}
@Override
protected Void visitDereferenceExpression(DereferenceExpression node, Void context)
{
if (columnReferences.contains(NodeRef.<Expression>of(node))) {
throw new SemanticException(EXPRESSION_NOT_CONSTANT, expression, "Constant expression cannot contain column references");
}
process(node.getBase(), context);
return null;
}
@Override
protected Void visitIdentifier(Identifier node, Void context)
{
throw new SemanticException(EXPRESSION_NOT_CONSTANT, expression, "Constant expression cannot contain column references");
}
@Override
protected Void visitFieldReference(FieldReference node, Void context)
{
throw new SemanticException(EXPRESSION_NOT_CONSTANT, expression, "Constant expression cannot contain column references");
}
View on GitHub (pinned to 55bb57d202)
Solutions
- Replace the column reference with a literal value or parameter placeholder (?)
- Wrap the value via a parameter (PREPARE/EXECUTE or session parameter) instead of referencing a column
- If row-dependent values are needed, move the expression into the query body rather than a constant context
Example fix
// before -- constant context SELECT * FROM t LIMIT :offset_col // after SELECT * FROM t LIMIT ? -- bind a literal integer
Defensive patterns
Strategy: validation
Validate before calling
if (expression instanceof DereferenceExpression && ConstantExpressionVerifier.isColumnReference(expression, metadata)) {
throw new IllegalArgumentException("Column reference not allowed in constant expression");
} Type guard
boolean isLiteralOnly(Expression e) {
return e instanceof Literal || e instanceof Parameter;
} Try / catch
try {
ConstantExpressionVerifier.verify(identity, expression, metadata, session);
} catch (SemanticException e) {
if (e.getCode() == SemanticErrorCode.EXPRESSION_NOT_CONSTANT) { /* substitute literal or parameter */ }
throw e;
} Prevention
- Never place column references (qualified or not) in constant-expression slots
- Use '?' parameters or literals where a constant is required
- Lint generated SQL for identifiers inside constant contexts
When it happens
Trigger: Passing a qualified column reference (a.b) as a constant expression — e.g. as a parameter value or generic-limitation-constant context — where the verifier's columnReferences set contains the dereference node.
Common situations: Using table-qualified column names in places expecting literals/parameters; generated SQL that substitutes identifiers instead of literals.
Related errors
- INVALID_PARAMETER_USAGE
- MISSING_ATTRIBUTE
- DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION
- NOT_SUPPORTED
- MISSING_TABLE
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/17d30643c556084a.
Report an issue: GitHub.