prestodb/presto · error · SQLException
Query has no columns (#%s)
Error message
Query has no columns (#%s)
What it means
Thrown when the statement finished successfully (no error) but the query result contained zero columns, which the JDBC ResultSet API cannot represent. Presto treats this as a driver-level failure rather than returning an empty metadata ResultSet. The finished query id is included in the message.
Source
Thrown at presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoResultSet.java:1749
}
private static List<Column> getColumns(StatementClient client, Consumer<QueryStats> progressCallback)
throws SQLException
{
while (client.isRunning()) {
QueryStatusInfo results = client.currentStatusInfo();
progressCallback.accept(QueryStats.create(results.getId(), results.getStats()));
List<Column> columns = results.getColumns();
if (columns != null) {
return columns;
}
client.advance();
}
verify(client.isFinished());
QueryStatusInfo results = client.finalStatusInfo();
if (results.getError() == null) {
throw new SQLException(format("Query has no columns (#%s)", results.getId()));
}
throw resultsException(results);
}
private static <T> Iterator<T> flatten(Iterator<Iterable<T>> iterator, long maxRows)
{
Iterator<T> rowsIterator = concat(transform(iterator, Iterable::iterator));
return (maxRows > 0) ? new LengthLimitedIterator<>(rowsIterator, maxRows) : rowsIterator;
}
private static class ResultsPageIterator
extends AbstractIterator<Iterable<List<Object>>>
{
private final StatementClient client;
private final Consumer<QueryStats> progressCallback;
private final WarningsManager warningsManager;
private final boolean isQuery;
View on GitHub (pinned to 55bb57d202)
Solutions
- Use executeUpdate() or execute() instead of executeQuery() for non-query statements
- Ensure the SQL actually returns columns, e.g. SELECT ... rather than INSERT/CREATE
- Check the query id in the message in the Presto coordinator logs to confirm what ran
- If dynamically building SQL, validate the statement kind before choosing executeQuery
Example fix
// before
ResultSet rs = stmt.executeQuery("CREATE TABLE t AS SELECT 1");
// after
boolean hasResultSet = stmt.execute("CREATE TABLE t AS SELECT 1");
ResultSet rs = hasResultSet ? stmt.getResultSet() : null; Defensive patterns
Strategy: validation
Validate before calling
String sql = sqlTrimmed.toLowerCase();
boolean looksLikeQuery = sql.startsWith("select") || sql.startsWith("values") || sql.startsWith("show") || sql.startsWith("describe") || sql.startsWith("explain");
if (!looksLikeQuery) throw new IllegalArgumentException("executeQuery requires a query; use execute/executeUpdate for: " + sqlTrimmed); Try / catch
try {
ResultSet rs = stmt.executeQuery(sql);
} catch (SQLException e) {
if (e.getMessage() != null && e.getMessage().contains("Query has no columns")) {
// fall back to non-query execution
stmt.execute(sql);
} else { throw e; }
} Prevention
- Route DDL/DML to executeUpdate or execute, not executeQuery
- Verify SQL kind before choosing the execution API in dynamic SQL code
- Log the query id from the message to trace coordinator-side execution
When it happens
Trigger: Executing a statement that produces no result columns (e.g. INSERT, CREATE TABLE, SET SESSION, CALL, or 'VALUES' mis-parsed) through Statement.executeQuery or via a ResultSet-producing path instead of executeUpdate/execute.
Common situations: Using executeQuery for DDL/DML statements that return no columns; running utility statements like PREPARE, RESET SESSION, or EXPLAIN ANALYZE expecting a ResultSet; driver version changes that tightened this validation.
Related errors
- SQL statement is not a query:
- 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/f6c236b8a603bcd9.
Report an issue: GitHub.