Skip to content

[BigQuery] Thread will hang forever when using executeSelect if you do not iterate over the entire ResultSet #3881

@raelik

Description

@raelik

Testing executeSelect on Java 21 on MacOS Sonoma 14.7.6, I found a concerning issue. If your process or thread attempts to end after creating a connection and calling executeSelect() without iterating over the entire ResultSet until next() returns false, it will hang forever.

Steps to reproduce

  1. Go through the usual steps of instantiating a BigQuery client, creating ConnectionSettings, calling createConnection on said client, and then call executeSelect() to get your BigQueryResult.
  2. Either let the process end, or don't iterate over the entire ResultSet contained in the BigQueryResult. It will hang.

Code example

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryResult;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.Connection;
import com.google.cloud.bigquery.ConnectionSettings;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import java.sql.ResultSet;
import java.sql.SQLException;

public class BQExecuteSelectTest {
  public static void main(String[] args) {
    try {
      if(args.length != 2)
        throw new IllegalArgumentException("Usage: BQExecuteSelectTest <project_id> <location>\n - Accepts SQL on STDIN");

      BigQuery bq = BigQueryOptions.newBuilder()
        .setProjectId(args[0])
        .setLocation(args[1]).build().getService();

      ConnectionSettings settings = ConnectionSettings.newBuilder()
        .setCreateSession(true)
        .setMaxResultPerPage(100)
        .setMaxResults(100L).build();

      Connection conn = bq.createConnection(settings);

      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
      BigQueryResult res = conn.executeSelect(reader.lines().collect(Collectors.joining("\n")));

      // Do nothing, or just don't finish iterating over res.getResultSet()
    } catch(IllegalArgumentException e) {
      System.out.println(e.getMessage());
    } catch(Exception e) {
      System.out.println("Something went wrong: " + e.getMessage());
    }
  }
}

Output

user@host bq_test % java -cp deps.jar:. BQExecuteSelectTest my-project us-east4 < test.sql
Jul 10, 2025 12:37:30 PM com.google.cloud.bigquery.ConnectionImpl getExecuteSelectResponse
INFO: 
 Using Fast Query Path
^C%  <-- Hit Ctrl-C here after waiting for several minutes.                                                                                                                                                                                                                                                       
user@host bq_test %

External references such as API reference guides

Any additional information below

When running a single command like this, you can simply Ctrl-C to end the process. But in a server environment where this could be running in different threads, it's very problematic. If a system (like mine) can allow interruption of ResultSet iteration (which can be necessary for very large result sets in specific scenarios), it can cause client threads to hang forever and never return, or background workers to wait forever and never become available to process other jobs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api: bigqueryIssues related to the googleapis/java-bigquery API.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions