4646import com .google .common .base .MoreObjects ;
4747import com .google .common .collect .ImmutableList ;
4848import com .google .common .util .concurrent .Uninterruptibles ;
49-
5049import org .joda .time .Duration ;
5150import org .slf4j .Logger ;
5251import org .slf4j .LoggerFactory ;
53-
5452import java .io .IOException ;
5553import java .util .Collection ;
5654import java .util .Collections ;
6159import java .util .Objects ;
6260import java .util .Random ;
6361import java .util .concurrent .TimeUnit ;
64-
6562import javax .annotation .Nullable ;
6663
6764/**
@@ -73,6 +70,7 @@ public class BigQueryTableRowIterator implements AutoCloseable {
7370 @ Nullable private TableReference ref ;
7471 @ Nullable private final String projectId ;
7572 @ Nullable private TableSchema schema ;
73+ @ Nullable private final JobConfigurationQuery queryConfig ;
7674 private final Bigquery client ;
7775 private String pageToken ;
7876 private Iterator <TableRow > iteratorOverCurrentBatch ;
@@ -89,25 +87,18 @@ public class BigQueryTableRowIterator implements AutoCloseable {
8987 // following interval to check the status of query execution job
9088 private static final Duration QUERY_COMPLETION_POLL_TIME = Duration .standardSeconds (1 );
9189
92- private final String query ;
93- // Whether to flatten query results.
94- private final boolean flattenResults ;
95- // Whether to use the BigQuery legacy SQL dialect..
96- private final boolean useLegacySql ;
9790 // Temporary dataset used to store query results.
9891 private String temporaryDatasetId = null ;
9992 // Temporary table used to store query results.
10093 private String temporaryTableId = null ;
10194
10295 private BigQueryTableRowIterator (
103- @ Nullable TableReference ref , @ Nullable String query , @ Nullable String projectId ,
104- Bigquery client , boolean flattenResults , boolean useLegacySql ) {
96+ @ Nullable TableReference ref , @ Nullable JobConfigurationQuery queryConfig ,
97+ @ Nullable String projectId , Bigquery client ) {
10598 this .ref = ref ;
106- this .query = query ;
99+ this .queryConfig = queryConfig ;
107100 this .projectId = projectId ;
108101 this .client = checkNotNull (client , "client" );
109- this .flattenResults = flattenResults ;
110- this .useLegacySql = useLegacySql ;
111102 }
112103
113104 /**
@@ -116,7 +107,7 @@ private BigQueryTableRowIterator(
116107 public static BigQueryTableRowIterator fromTable (TableReference ref , Bigquery client ) {
117108 checkNotNull (ref , "ref" );
118109 checkNotNull (client , "client" );
119- return new BigQueryTableRowIterator (ref , null , ref .getProjectId (), client , true , true );
110+ return new BigQueryTableRowIterator (ref , null , ref .getProjectId (), client );
120111 }
121112
122113 /**
@@ -135,23 +126,39 @@ public static BigQueryTableRowIterator fromQuery(
135126 * Constructs a {@code BigQueryTableRowIterator} that reads from the results of executing the
136127 * specified query in the specified project.
137128 */
129+ @ Deprecated
138130 public static BigQueryTableRowIterator fromQuery (
139131 String query , String projectId , Bigquery client , @ Nullable Boolean flattenResults ,
140132 @ Nullable Boolean useLegacySql ) {
141133 checkNotNull (query , "query" );
142134 checkNotNull (projectId , "projectId" );
143135 checkNotNull (client , "client" );
144- return new BigQueryTableRowIterator (null , query , projectId , client ,
145- MoreObjects .firstNonNull (flattenResults , Boolean .TRUE ),
146- MoreObjects .firstNonNull (useLegacySql , Boolean .TRUE ));
136+ JobConfigurationQuery queryConfig = new JobConfigurationQuery ()
137+ .setFlattenResults (MoreObjects .firstNonNull (flattenResults , Boolean .TRUE ))
138+ .setPriority ("BATCH" )
139+ .setQuery (query )
140+ .setUseLegacySql (MoreObjects .firstNonNull (useLegacySql , Boolean .TRUE ));
141+ return new BigQueryTableRowIterator (null , queryConfig , projectId , client );
142+ }
143+
144+ /**
145+ * Constructs a {@code BigQueryTableRowIterator} that reads from the results of executing the
146+ * specified query in the specified project.
147+ */
148+ public static BigQueryTableRowIterator fromQuery (
149+ JobConfigurationQuery queryConfig , String projectId , Bigquery client ) {
150+ checkNotNull (queryConfig , "queryConfig" );
151+ checkNotNull (projectId , "projectId" );
152+ checkNotNull (client , "client" );
153+ return new BigQueryTableRowIterator (null , queryConfig , projectId , client );
147154 }
148155
149156 /**
150157 * Opens the table for read.
151158 * @throws IOException on failure
152159 */
153160 public void open () throws IOException , InterruptedException {
154- if (query != null ) {
161+ if (queryConfig != null ) {
155162 ref = executeQueryAndWaitForCompletion ();
156163 }
157164 // Get table schema.
@@ -401,15 +408,17 @@ private void deleteDataset(String datasetId) throws IOException, InterruptedExce
401408 */
402409 private TableReference executeQueryAndWaitForCompletion ()
403410 throws IOException , InterruptedException {
411+ checkState (projectId != null , "Unable to execute a query without a configured project id" );
412+ checkState (queryConfig != null , "Unable to execute a query without a configured query" );
404413 // Dry run query to get source table location
405414 Job dryRunJob = new Job ()
406415 .setConfiguration (new JobConfiguration ()
407- .setQuery (new JobConfigurationQuery ()
408- .setQuery (query ))
416+ .setQuery (queryConfig )
409417 .setDryRun (true ));
410418 JobStatistics jobStats = executeWithBackOff (
411419 client .jobs ().insert (projectId , dryRunJob ),
412- String .format ("Error when trying to dry run query %s." , query )).getStatistics ();
420+ String .format ("Error when trying to dry run query %s." ,
421+ queryConfig .toPrettyString ())).getStatistics ();
413422
414423 // Let BigQuery to pick default location if the query does not read any tables.
415424 String location = null ;
@@ -428,30 +437,27 @@ private TableReference executeQueryAndWaitForCompletion()
428437 createDataset (temporaryDatasetId , location );
429438 Job job = new Job ();
430439 JobConfiguration config = new JobConfiguration ();
431- JobConfigurationQuery queryConfig = new JobConfigurationQuery ();
432440 config .setQuery (queryConfig );
433441 job .setConfiguration (config );
434- queryConfig .setQuery (query );
435- queryConfig .setAllowLargeResults (true );
436- queryConfig .setFlattenResults (flattenResults );
437- queryConfig .setUseLegacySql (useLegacySql );
438-
439442
440443 TableReference destinationTable = new TableReference ();
441444 destinationTable .setProjectId (projectId );
442445 destinationTable .setDatasetId (temporaryDatasetId );
443446 destinationTable .setTableId (temporaryTableId );
444447 queryConfig .setDestinationTable (destinationTable );
448+ queryConfig .setAllowLargeResults (Boolean .TRUE );
445449
446450 Job queryJob = executeWithBackOff (
447451 client .jobs ().insert (projectId , job ),
448- String .format ("Error when trying to execute the job for query %s." , query ));
452+ String .format ("Error when trying to execute the job for query %s." ,
453+ queryConfig .toPrettyString ()));
449454 JobReference jobId = queryJob .getJobReference ();
450455
451456 while (true ) {
452457 Job pollJob = executeWithBackOff (
453458 client .jobs ().get (projectId , jobId .getJobId ()),
454- String .format ("Error when trying to get status of the job for query %s." , query ));
459+ String .format ("Error when trying to get status of the job for query %s." ,
460+ queryConfig .toPrettyString ()));
455461 JobStatus status = pollJob .getStatus ();
456462 if (status .getState ().equals ("DONE" )) {
457463 // Job is DONE, but did not necessarily succeed.
@@ -461,7 +467,9 @@ private TableReference executeQueryAndWaitForCompletion()
461467 } else {
462468 // There will be no temporary table to delete, so null out the reference.
463469 temporaryTableId = null ;
464- throw new IOException ("Executing query " + query + " failed: " + error .getMessage ());
470+ throw new IOException (
471+ String .format ("Executing query %s failed: %s" ,
472+ queryConfig .toPrettyString (), error .getMessage ()));
465473 }
466474 }
467475 Uninterruptibles .sleepUninterruptibly (
0 commit comments