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

  1. Use executeUpdate() or execute() instead of executeQuery() for non-query statements
  2. Ensure the SQL actually returns columns, e.g. SELECT ... rather than INSERT/CREATE
  3. Check the query id in the message in the Presto coordinator logs to confirm what ran
  4. 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

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


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