prestodb/presto · error · SQLException
SQL statement is not a query:
Error message
SQL statement is not a query:
What it means
Statement.executeQuery() calls execute(sql) and, if it returns false (meaning the statement produced no ResultSet — i.e. it was an update/DDL statement), throws this SQLException including the offending SQL text. executeQuery is only valid for statements that return rows.
Source
Thrown at presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoStatement.java:80
this.connection = new AtomicReference<>(requireNonNull(connection, "connection is null"));
}
public void setProgressMonitor(Consumer<QueryStats> progressMonitor)
{
progressCallback.set(Optional.of(requireNonNull(progressMonitor, "progressMonitor is null")));
}
public void clearProgressMonitor()
{
progressCallback.set(Optional.empty());
}
@Override
public ResultSet executeQuery(String sql)
throws SQLException
{
if (!execute(sql)) {
throw new SQLException("SQL statement is not a query: " + sql);
}
return currentResult.get();
}
@Override
public void close()
throws SQLException
{
connection.set(null);
closeResultSet();
}
@Override
public int getMaxFieldSize()
throws SQLException
{
checkOpen();
return 0;View on GitHub (pinned to 55bb57d202)
Solutions
- Use executeUpdate() for DML, or execute()/executeLargeUpdate() for DDL and utility statements
- Check execute()'s boolean return and only call getResultSet() when true
- CAST the statement or add a trivial SELECT if you truly need rows, though the correct API is preferred
Example fix
// before
ResultSet rs = stmt.executeQuery("DROP TABLE t");
// after
boolean hasRs = stmt.execute("DROP TABLE t");
// hasRs == false: statement is not a query Defensive patterns
Strategy: validation
Validate before calling
String s = sql.trim().toLowerCase();
boolean nonQuery = s.startsWith("insert") || s.startsWith("update") || s.startsWith("delete") || s.startsWith("create") || s.startsWith("drop") || s.startsWith("alter") || s.startsWith("set ") || s.startsWith("call") || s.startsWith("grant") || s.startsWith("revoke");
if (nonQuery) throw new IllegalArgumentException("Use execute/executeUpdate, not executeQuery, for: " + s); Try / catch
try (ResultSet rs = stmt.executeQuery(sql)) {
// consume rows
} catch (SQLException e) {
if (e.getMessage() != null && e.getMessage().startsWith("SQL statement is not a query")) {
stmt.execute(sql); // re-run as non-query
} else { throw e; }
} Prevention
- Use executeUpdate for DML and execute for DDL/utility statements
- In generic execution helpers, call execute() and branch on its boolean return
- Review generated SQL to ensure query-only paths receive SELECT statements
When it happens
Trigger: Calling PrestoStatement.executeQuery with INSERT/UPDATE/DELETE/CREATE/DROP/ALTER/SET SESSION/CALL — any statement where execute() returns false because there is no result set.
Common situations: Running DDL or DML through executeQuery out of habit; framework code that always calls executeQuery; migration scripts executed via a query-only API; syntax confusion where a Presto utility statement has no result columns.
Related errors
- Query has no columns (#%s)
- Max field size must be positive
- Max rows exceeds limit of 2147483647
- Max rows must be positive
- NOT_SUPPORTED
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/7a708593ef6509ed.
Report an issue: GitHub.