@@ -59,12 +59,30 @@ func (c *Client) Read(ctx context.Context, src ReadSource, options ...ReadOption
59
59
case * Job :
60
60
return src .Read (ctx , options ... )
61
61
case * Query :
62
- // For compatibility, support Query values created by literal, rather
63
- // than Client.Query.
62
+ // Query used not to contain a QueryConfig. By moving its
63
+ // top-level fields down into a QueryConfig field, we break
64
+ // code that uses a Query literal. If users make the minimal
65
+ // change to fix this (e.g. moving the "Q" field into a nested
66
+ // QueryConfig within the Query), they will end up with a Query
67
+ // that has no Client. It's preferable to make Read continue
68
+ // to work in this case too, at least until we delete Read
69
+ // completely. So we copy QueryConfig into a Query with an
70
+ // actual client.
64
71
if src .client == nil {
65
- src .client = c
72
+ src = & Query {
73
+ client : c ,
74
+ QueryConfig : src .QueryConfig ,
75
+ Q : src .Q ,
76
+ DefaultProjectID : src .DefaultProjectID ,
77
+ DefaultDatasetID : src .DefaultDatasetID ,
78
+ }
66
79
}
67
80
return src .Read (ctx , options ... )
81
+ case * QueryConfig :
82
+ // For compatibility, support QueryConfig values created by literal, rather
83
+ // than Client.Query.
84
+ q := & Query {client : c , QueryConfig : * src }
85
+ return q .Read (ctx , options ... )
68
86
case * Table :
69
87
return src .Read (ctx , options ... )
70
88
}
@@ -194,14 +212,42 @@ func (opt ignoreUnknownValues) customizeLoad(conf *bq.JobConfigurationLoad) {
194
212
conf .IgnoreUnknownValues = true
195
213
}
196
214
215
+ // CreateDisposition returns an Option that specifies the TableCreateDisposition to use.
216
+ // Deprecated: use the CreateDisposition field in Query, CopyConfig or LoadConfig instead.
217
+ func CreateDisposition (disp TableCreateDisposition ) Option { return disp }
218
+
219
+ func (opt TableCreateDisposition ) implementsOption () {}
220
+
221
+ func (opt TableCreateDisposition ) customizeCopy (conf * bq.JobConfigurationTableCopy ) {
222
+ conf .CreateDisposition = string (opt )
223
+ }
224
+
197
225
func (opt TableCreateDisposition ) customizeLoad (conf * bq.JobConfigurationLoad ) {
198
226
conf .CreateDisposition = string (opt )
199
227
}
200
228
229
+ func (opt TableCreateDisposition ) customizeQuery (conf * bq.JobConfigurationQuery ) {
230
+ conf .CreateDisposition = string (opt )
231
+ }
232
+
233
+ // WriteDisposition returns an Option that specifies the TableWriteDisposition to use.
234
+ // Deprecated: use the WriteDisposition field in Query, CopyConfig or LoadConfig instead.
235
+ func WriteDisposition (disp TableWriteDisposition ) Option { return disp }
236
+
237
+ func (opt TableWriteDisposition ) implementsOption () {}
238
+
239
+ func (opt TableWriteDisposition ) customizeCopy (conf * bq.JobConfigurationTableCopy ) {
240
+ conf .WriteDisposition = string (opt )
241
+ }
242
+
201
243
func (opt TableWriteDisposition ) customizeLoad (conf * bq.JobConfigurationLoad ) {
202
244
conf .WriteDisposition = string (opt )
203
245
}
204
246
247
+ func (opt TableWriteDisposition ) customizeQuery (conf * bq.JobConfigurationQuery ) {
248
+ conf .WriteDisposition = string (opt )
249
+ }
250
+
205
251
type extractOption interface {
206
252
customizeExtract (conf * bq.JobConfigurationExtract )
207
253
}
@@ -299,6 +345,9 @@ func (c *Client) Copy(ctx context.Context, dst Destination, src Source, options
299
345
return c .cp (ctx , dst , src , options )
300
346
case * Query :
301
347
return c .query (ctx , dst , src , options )
348
+ case * QueryConfig :
349
+ q := & Query {QueryConfig : * src }
350
+ return c .query (ctx , dst , q , options )
302
351
}
303
352
case * GCSReference :
304
353
if src , ok := src .(* Table ); ok {
@@ -322,3 +371,171 @@ type Destination interface {
322
371
type ReadSource interface {
323
372
implementsReadSource ()
324
373
}
374
+
375
+ type queryOption interface {
376
+ customizeQuery (conf * bq.JobConfigurationQuery )
377
+ }
378
+
379
+ // DisableQueryCache returns an Option that prevents results being fetched from the query cache.
380
+ // If this Option is not used, results are fetched from the cache if they are available.
381
+ // The query cache is a best-effort cache that is flushed whenever tables in the query are modified.
382
+ // Cached results are only available when TableID is unspecified in the query's destination Table.
383
+ // For more information, see https://cloud.google.com/bigquery/querying-data#querycaching
384
+ //
385
+ // Deprecated: use Query.DisableQueryCache instead.
386
+ func DisableQueryCache () Option { return disableQueryCache {} }
387
+
388
+ type disableQueryCache struct {}
389
+
390
+ func (opt disableQueryCache ) implementsOption () {}
391
+
392
+ func (opt disableQueryCache ) customizeQuery (conf * bq.JobConfigurationQuery ) {
393
+ f := false
394
+ conf .UseQueryCache = & f
395
+ }
396
+
397
+ // DisableFlattenedResults returns an Option that prevents results being flattened.
398
+ // If this Option is not used, results from nested and repeated fields are flattened.
399
+ // DisableFlattenedResults implies AllowLargeResults
400
+ // For more information, see https://cloud.google.com/bigquery/docs/data#nested
401
+ // Deprecated: use Query.DisableFlattenedResults instead.
402
+ func DisableFlattenedResults () Option { return disableFlattenedResults {} }
403
+
404
+ type disableFlattenedResults struct {}
405
+
406
+ func (opt disableFlattenedResults ) implementsOption () {}
407
+
408
+ func (opt disableFlattenedResults ) customizeQuery (conf * bq.JobConfigurationQuery ) {
409
+ f := false
410
+ conf .FlattenResults = & f
411
+ // DisableFlattenedResults implies AllowLargeResults
412
+ allowLargeResults {}.customizeQuery (conf )
413
+ }
414
+
415
+ // AllowLargeResults returns an Option that allows the query to produce arbitrarily large result tables.
416
+ // The destination must be a table.
417
+ // When using this option, queries will take longer to execute, even if the result set is small.
418
+ // For additional limitations, see https://cloud.google.com/bigquery/querying-data#largequeryresults
419
+ // Deprecated: use Query.AllowLargeResults instead.
420
+ func AllowLargeResults () Option { return allowLargeResults {} }
421
+
422
+ type allowLargeResults struct {}
423
+
424
+ func (opt allowLargeResults ) implementsOption () {}
425
+
426
+ func (opt allowLargeResults ) customizeQuery (conf * bq.JobConfigurationQuery ) {
427
+ conf .AllowLargeResults = true
428
+ }
429
+
430
+ // JobPriority returns an Option that causes a query to be scheduled with the specified priority.
431
+ // The default priority is InteractivePriority.
432
+ // For more information, see https://cloud.google.com/bigquery/querying-data#batchqueries
433
+ // Deprecated: use Query.Priority instead.
434
+ func JobPriority (priority string ) Option { return jobPriority (priority ) }
435
+
436
+ type jobPriority string
437
+
438
+ func (opt jobPriority ) implementsOption () {}
439
+
440
+ func (opt jobPriority ) customizeQuery (conf * bq.JobConfigurationQuery ) {
441
+ conf .Priority = string (opt )
442
+ }
443
+
444
+ // MaxBillingTier returns an Option that sets the maximum billing tier for a Query.
445
+ // Queries that have resource usage beyond this tier will fail (without
446
+ // incurring a charge). If this Option is not used, the project default will be used.
447
+ // Deprecated: use Query.MaxBillingTier instead.
448
+ func MaxBillingTier (tier int ) Option { return maxBillingTier (tier ) }
449
+
450
+ type maxBillingTier int
451
+
452
+ func (opt maxBillingTier ) implementsOption () {}
453
+
454
+ func (opt maxBillingTier ) customizeQuery (conf * bq.JobConfigurationQuery ) {
455
+ tier := int64 (opt )
456
+ conf .MaximumBillingTier = & tier
457
+ }
458
+
459
+ // MaxBytesBilled returns an Option that limits the number of bytes billed for
460
+ // this job. Queries that would exceed this limit will fail (without incurring
461
+ // a charge).
462
+ // If this Option is not used, or bytes is < 1, the project default will be
463
+ // used.
464
+ // Deprecated: use Query.MaxBytesBilled instead.
465
+ func MaxBytesBilled (bytes int64 ) Option { return maxBytesBilled (bytes ) }
466
+
467
+ type maxBytesBilled int64
468
+
469
+ func (opt maxBytesBilled ) implementsOption () {}
470
+
471
+ func (opt maxBytesBilled ) customizeQuery (conf * bq.JobConfigurationQuery ) {
472
+ if opt >= 1 {
473
+ conf .MaximumBytesBilled = int64 (opt )
474
+ }
475
+ }
476
+
477
+ // QueryUseStandardSQL returns an Option that set the query to use standard SQL.
478
+ // The default setting is false (using legacy SQL).
479
+ // Deprecated: use Query.UseStandardSQL instead.
480
+ func QueryUseStandardSQL () Option { return queryUseStandardSQL {} }
481
+
482
+ type queryUseStandardSQL struct {}
483
+
484
+ func (opt queryUseStandardSQL ) implementsOption () {}
485
+
486
+ func (opt queryUseStandardSQL ) customizeQuery (conf * bq.JobConfigurationQuery ) {
487
+ conf .UseLegacySql = false
488
+ conf .ForceSendFields = append (conf .ForceSendFields , "UseLegacySql" )
489
+ }
490
+
491
+ func (c * Client ) query (ctx context.Context , dst * Table , src * Query , options []Option ) (* Job , error ) {
492
+ job , options := initJobProto (c .projectID , options )
493
+ payload := & bq.JobConfigurationQuery {}
494
+
495
+ dst .customizeQueryDst (payload )
496
+
497
+ // QueryConfig now contains a Dst field. If it is set, it will override dst.
498
+ // This should not affect existing client code which does not set QueryConfig.Dst.
499
+ src .QueryConfig .customizeQuerySrc (payload )
500
+
501
+ // For compatability, allow some legacy fields to be set directly on the query.
502
+ // TODO(jba): delete this code when deleting Client.Copy.
503
+ if src .Q != "" {
504
+ payload .Query = src .Q
505
+ }
506
+ if src .DefaultProjectID != "" || src .DefaultDatasetID != "" {
507
+ payload .DefaultDataset = & bq.DatasetReference {
508
+ DatasetId : src .DefaultDatasetID ,
509
+ ProjectId : src .DefaultProjectID ,
510
+ }
511
+ }
512
+ // end of compatability code.
513
+
514
+ for _ , opt := range options {
515
+ o , ok := opt .(queryOption )
516
+ if ! ok {
517
+ return nil , fmt .Errorf ("option (%#v) not applicable to dst/src pair: dst: %T ; src: %T" , opt , dst , src )
518
+ }
519
+ o .customizeQuery (payload )
520
+ }
521
+
522
+ job .Configuration = & bq.JobConfiguration {
523
+ Query : payload ,
524
+ }
525
+ j , err := c .service .insertJob (ctx , job , c .projectID )
526
+ if err != nil {
527
+ return nil , err
528
+ }
529
+ j .isQuery = true
530
+ return j , nil
531
+ }
532
+
533
+ // Read submits a query for execution and returns the results via an Iterator.
534
+ // Deprecated: Call Read on the Job returned by Query.Run instead.
535
+ func (q * Query ) Read (ctx context.Context , options ... ReadOption ) (* Iterator , error ) {
536
+ job , err := q .Run (ctx )
537
+ if err != nil {
538
+ return nil , err
539
+ }
540
+ return job .Read (ctx , options ... )
541
+ }
0 commit comments