prestodb/presto · error · SQLException

This method cannot be called on PreparedStatement

Error message

This method cannot be called on PreparedStatement

What it means

PrestoPreparedStatement implements java.sql.PreparedStatement, whose contract forbids executing raw SQL text through the Statement-inherited methods. Calling executeQuery(String) on a PreparedStatement would bypass parameter binding, so the driver unconditionally throws SQLException with this message. The SQL must instead be supplied at prepareStatement() time and executed via the no-argument executeQuery().

Source

Thrown at presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoPreparedStatement.java:701

    @Override
    public void setBlob(int parameterIndex, InputStream inputStream)
            throws SQLException
    {
        throw new SQLFeatureNotSupportedException("setBlob");
    }

    @Override
    public void setNClob(int parameterIndex, Reader reader)
            throws SQLException
    {
        throw new SQLFeatureNotSupportedException("setNClob");
    }

    @Override
    public ResultSet executeQuery(String sql)
            throws SQLException
    {
        throw new SQLException("This method cannot be called on PreparedStatement");
    }

    @Override
    public int executeUpdate(String sql)
            throws SQLException
    {
        throw new SQLException("This method cannot be called on PreparedStatement");
    }

    @Override
    public int executeUpdate(String sql, int autoGeneratedKeys)
            throws SQLException
    {
        throw new SQLException("This method cannot be called on PreparedStatement");
    }

    @Override
    public int executeUpdate(String sql, int[] columnIndexes)

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Move the SQL into connection.prepareStatement(sql) and call ps.executeQuery() with no arguments
  2. If the SQL is not parameterized, obtain a Statement via connection.createStatement() and keep executeQuery(sql)
  3. Fix generic helper methods to detect PreparedStatement (instanceof) and use the no-arg execute path
  4. Update the failing call site so it never passes a SQL string to a PreparedStatement

Example fix

// before
PreparedStatement ps = conn.prepareStatement("SELECT * FROM t WHERE id = ?");
ps.setLong(1, id);
ResultSet rs = ps.executeQuery("SELECT * FROM t WHERE id = ?");
// after
PreparedStatement ps = conn.prepareStatement("SELECT * FROM t WHERE id = ?");
ps.setLong(1, id);
ResultSet rs = ps.executeQuery();
Defensive patterns

Strategy: validation

Validate before calling

if (stmt instanceof java.sql.PreparedStatement) {
    ((java.sql.PreparedStatement) stmt).executeQuery();
} else {
    stmt.executeQuery(sql);
}

Type guard

boolean isPreparedStatement(java.sql.Statement s) { return s instanceof java.sql.PreparedStatement; }

Try / catch

try {
    rs = ps.executeQuery();
} catch (SQLException e) {
    if (e.getMessage().contains("cannot be called on PreparedStatement")) {
        throw new IllegalStateException("SQL text must be passed to prepareStatement(), not executeQuery(String)", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling prestoPreparedStatement.executeQuery("SELECT ...") with a SQL string on an object obtained from connection.prepareStatement(sql). The throw is unconditional — there is no state in which this method succeeds.

Common situations: Refactored code that switched from createStatement() to prepareStatement() but kept the old executeQuery(sql) call; generic query-runner utilities that accept a Statement and a SQL string and dispatch to executeQuery(sql); ORMs or connection pools sharing a code path between Statement and PreparedStatement.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/7e668ee26b1809c1. Report an issue: GitHub.