embulk-output-bigquery 0.2.3 → 0.3.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -12
  3. data/CHANGELOG.md +18 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +165 -39
  7. data/Rakefile +11 -0
  8. data/embulk-output-bigquery.gemspec +20 -0
  9. data/example/config_client_options.yml +33 -0
  10. data/example/config_csv.yml +30 -0
  11. data/example/config_delete_in_advance.yml +29 -0
  12. data/example/config_expose_errors.yml +30 -0
  13. data/example/config_guess_from_embulk_schema.yml +29 -0
  14. data/example/config_guess_with_column_options.yml +40 -0
  15. data/example/config_gzip.yml +30 -0
  16. data/example/config_jsonl.yml +30 -0
  17. data/example/config_mode_append.yml +30 -0
  18. data/example/config_mode_append_direct.yml +30 -0
  19. data/example/config_payload_column.yml +20 -0
  20. data/example/config_payload_column_index.yml +20 -0
  21. data/example/config_prevent_duplicate_insert.yml +30 -0
  22. data/example/config_replace.yml +30 -0
  23. data/example/config_replace_backup.yml +32 -0
  24. data/example/config_skip_file_generation.yml +32 -0
  25. data/example/config_table_strftime.yml +30 -0
  26. data/example/config_template_table.yml +21 -0
  27. data/example/config_uncompressed.yml +30 -0
  28. data/example/config_with_rehearsal.yml +32 -0
  29. data/example/example.csv +17 -0
  30. data/example/example.jsonl +16 -0
  31. data/example/example.yml +30 -0
  32. data/example/json_key.json +12 -0
  33. data/example/nested_example.jsonl +16 -0
  34. data/example/schema.json +30 -0
  35. data/example/schema_expose_errors.json +30 -0
  36. data/lib/embulk/output/bigquery.rb +388 -3
  37. data/lib/embulk/output/bigquery/bigquery_client.rb +396 -0
  38. data/lib/embulk/output/bigquery/file_writer.rb +103 -0
  39. data/lib/embulk/output/bigquery/helper.rb +78 -0
  40. data/lib/embulk/output/bigquery/value_converter_factory.rb +292 -0
  41. data/test/helper.rb +13 -0
  42. data/test/test_bigquery_client.rb +166 -0
  43. data/test/test_configure.rb +254 -0
  44. data/test/test_example.rb +34 -0
  45. data/test/test_file_writer.rb +129 -0
  46. data/test/test_helper.rb +103 -0
  47. data/test/test_transaction.rb +129 -0
  48. data/test/test_value_converter_factory.rb +316 -0
  49. metadata +114 -45
  50. data/build.gradle +0 -80
  51. data/config/checkstyle/checkstyle.xml +0 -128
  52. data/config/checkstyle/default.xml +0 -108
  53. data/gradle/wrapper/gradle-wrapper.jar +0 -0
  54. data/gradle/wrapper/gradle-wrapper.properties +0 -6
  55. data/gradlew +0 -164
  56. data/gradlew.bat +0 -90
  57. data/settings.gradle +0 -2
  58. data/src/main/java/org/embulk/output/BigqueryAuthentication.java +0 -117
  59. data/src/main/java/org/embulk/output/BigqueryOutputPlugin.java +0 -508
  60. data/src/main/java/org/embulk/output/BigqueryWriter.java +0 -575
  61. data/src/test/java/org/embulk/output/TestBigqueryAuthentication.java +0 -5
  62. data/src/test/java/org/embulk/output/TestBigqueryOutputPlugin.java +0 -5
  63. data/src/test/java/org/embulk/output/TestBigqueryWriter.java +0 -5
@@ -1,575 +0,0 @@
1
- package org.embulk.output;
2
-
3
- import com.fasterxml.jackson.core.type.TypeReference;
4
- import com.fasterxml.jackson.databind.ObjectMapper;
5
- import com.google.api.client.googleapis.json.GoogleJsonResponseException;
6
- import com.google.api.client.googleapis.media.MediaHttpUploader;
7
- import com.google.api.client.googleapis.media.MediaHttpUploaderProgressListener;
8
- import com.google.api.client.http.InputStreamContent;
9
- import com.google.api.services.bigquery.Bigquery;
10
- import com.google.api.services.bigquery.Bigquery.Jobs.Insert;
11
- import com.google.api.services.bigquery.Bigquery.Tables;
12
- import com.google.api.services.bigquery.model.ErrorProto;
13
- import com.google.api.services.bigquery.model.Job;
14
- import com.google.api.services.bigquery.model.JobConfiguration;
15
- import com.google.api.services.bigquery.model.JobConfigurationLoad;
16
- import com.google.api.services.bigquery.model.JobConfigurationTableCopy;
17
- import com.google.api.services.bigquery.model.JobReference;
18
- import com.google.api.services.bigquery.model.JobStatistics;
19
- import com.google.api.services.bigquery.model.Table;
20
- import com.google.api.services.bigquery.model.TableFieldSchema;
21
- import com.google.api.services.bigquery.model.TableReference;
22
- import com.google.api.services.bigquery.model.TableSchema;
23
- import com.google.common.base.Optional;
24
- import com.google.common.collect.ImmutableList;
25
- import org.apache.commons.codec.binary.Hex;
26
- import org.embulk.spi.Exec;
27
- import org.slf4j.Logger;
28
-
29
- import java.io.BufferedInputStream;
30
- import java.io.File;
31
- import java.io.FileInputStream;
32
- import java.io.FileNotFoundException;
33
-
34
- import java.io.IOException;
35
- import java.security.GeneralSecurityException;
36
- import java.security.MessageDigest;
37
- import java.security.NoSuchAlgorithmException;
38
- import java.util.List;
39
- import java.util.concurrent.TimeoutException;
40
-
41
- public class BigqueryWriter
42
- {
43
- private final Logger log = Exec.getLogger(BigqueryWriter.class);
44
- private final String project;
45
- private final String dataset;
46
- private final String table;
47
- private final boolean autoCreateTable;
48
- private final Optional<String> schemaPath;
49
- private final Optional<String> templateTable;
50
- private final TableSchema tableSchema;
51
- private final String sourceFormat;
52
- private final String fieldDelimiter;
53
- private final int maxBadRecords;
54
- private final String encoding;
55
- private final boolean preventDuplicateInsert;
56
- private final long jobStatusMaxPollingTime;
57
- private final long jobStatusPollingInterval;
58
- private final boolean isSkipJobResultCheck;
59
- private final boolean ignoreUnknownValues;
60
- private final boolean allowQuotedNewlines;
61
- private final Bigquery bigQueryClient;
62
-
63
- public BigqueryWriter(Builder builder)
64
- throws IOException, GeneralSecurityException
65
- {
66
- this.project = builder.project;
67
- this.dataset = builder.dataset;
68
- this.table = builder.table;
69
- this.autoCreateTable = builder.autoCreateTable;
70
- this.schemaPath = builder.schemaPath;
71
- this.templateTable = builder.templateTable;
72
- this.sourceFormat = builder.sourceFormat.toUpperCase();
73
- this.fieldDelimiter = builder.fieldDelimiter;
74
- this.maxBadRecords = builder.maxBadRecords;
75
- this.encoding = builder.encoding.toUpperCase();
76
- this.preventDuplicateInsert = builder.preventDuplicateInsert;
77
- this.jobStatusMaxPollingTime = builder.jobStatusMaxPollingTime;
78
- this.jobStatusPollingInterval = builder.jobStatusPollingInterval;
79
- this.isSkipJobResultCheck = builder.isSkipJobResultCheck;
80
- this.ignoreUnknownValues = builder.ignoreUnknownValues;
81
- this.allowQuotedNewlines = builder.allowQuotedNewlines;
82
-
83
- BigqueryAuthentication auth = new BigqueryAuthentication(
84
- builder.authMethod, builder.serviceAccountEmail, builder.p12KeyFilePath,
85
- builder.jsonKeyFilePath, builder.applicationName
86
- );
87
- this.bigQueryClient = auth.getBigqueryClient();
88
-
89
- checkConfig();
90
-
91
- if (autoCreateTable) {
92
- if (schemaPath.isPresent()) {
93
- this.tableSchema = createTableSchema();
94
- }
95
- else {
96
- this.tableSchema = fetchTableSchema();
97
- }
98
- }
99
- else {
100
- this.tableSchema = null;
101
- }
102
- }
103
-
104
- private String getJobStatus(String project, JobReference jobRef) throws JobFailedException
105
- {
106
- try {
107
- Job job = bigQueryClient.jobs().get(project, jobRef.getJobId()).execute();
108
-
109
- List<ErrorProto> errors = job.getStatus().getErrors();
110
- if (errors != null) {
111
- for (ErrorProto error : errors) {
112
- log.error(String.format("Error: reason[%s][%s] location:[%s]", error.getReason(), error.getMessage(), error.getLocation()));
113
- }
114
- }
115
-
116
- ErrorProto fatalError = job.getStatus().getErrorResult();
117
- if (fatalError != null) {
118
- throw new JobFailedException(String.format("Job failed. job id:[%s] reason:[%s][%s] status:[FAILED]", jobRef.getJobId(), fatalError.getReason(), fatalError.getMessage()));
119
- }
120
-
121
- String jobStatus = job.getStatus().getState();
122
- if (jobStatus.equals("DONE")) {
123
- JobStatistics statistics = job.getStatistics();
124
- log.info(String.format("Job statistics [%s]", statistics.getLoad()));
125
- }
126
- return jobStatus;
127
- }
128
- catch (IOException ex) {
129
- log.warn(ex.getMessage());
130
- return "UNKNOWN";
131
- }
132
- }
133
-
134
- private void getJobStatusUntilDone(String project, JobReference jobRef) throws TimeoutException, JobFailedException
135
- {
136
- long startTime = System.currentTimeMillis();
137
- long elapsedTime;
138
-
139
- try {
140
- while (true) {
141
- String jobStatus = getJobStatus(project, jobRef);
142
- elapsedTime = System.currentTimeMillis() - startTime;
143
- if (jobStatus.equals("DONE")) {
144
- log.info(String.format("Job completed successfully. job id:[%s] elapsed_time:%dms status:[%s]", jobRef.getJobId(), elapsedTime, "SUCCESS"));
145
- break;
146
- }
147
- else if (elapsedTime > jobStatusMaxPollingTime * 1000) {
148
- throw new TimeoutException(String.format("Checking job status...Timeout. job id:[%s] elapsed_time:%dms status:[%s]", jobRef.getJobId(), elapsedTime, "TIMEOUT"));
149
- }
150
- else {
151
- log.info(String.format("Checking job status... job id:[%s] elapsed_time:%dms status:[%s]", jobRef.getJobId(), elapsedTime, jobStatus));
152
- }
153
- Thread.sleep(jobStatusPollingInterval * 1000);
154
- }
155
- }
156
- catch (InterruptedException ex) {
157
- log.warn(ex.getMessage());
158
- }
159
- }
160
-
161
- public void executeLoad(String project, String dataset, String table, String localFilePath)
162
- throws NoSuchAlgorithmException, TimeoutException, JobFailedException, IOException
163
- {
164
- log.info(String.format("Job preparing... project:%s dataset:%s table:%s", project, dataset, table));
165
-
166
- Job job = new Job();
167
- JobReference jobRef = new JobReference();
168
- JobConfiguration jobConfig = new JobConfiguration().setLoad(setLoadConfig(project, dataset, table));
169
- job.setConfiguration(jobConfig);
170
-
171
- if (preventDuplicateInsert) {
172
- ImmutableList<String> elements = ImmutableList.of(
173
- getLocalMd5hash(localFilePath), dataset, table,
174
- String.valueOf(tableSchema), sourceFormat, fieldDelimiter, String.valueOf(maxBadRecords),
175
- encoding, String.valueOf(ignoreUnknownValues), String.valueOf(allowQuotedNewlines)
176
- );
177
- String jobId = createJobId(elements);
178
-
179
- jobRef.setJobId(jobId);
180
- job.setJobReference(jobRef);
181
- }
182
-
183
- File file = new File(localFilePath);
184
- InputStreamContent mediaContent = new InputStreamContent("application/octet-stream",
185
- new BufferedInputStream(
186
- new FileInputStream(file)));
187
- mediaContent.setLength(file.length());
188
-
189
- Insert insert = bigQueryClient.jobs().insert(project, job, mediaContent);
190
- insert.setProjectId(project);
191
- insert.setDisableGZipContent(true);
192
-
193
- // @see https://code.google.com/p/google-api-java-client/wiki/MediaUpload
194
- UploadProgressListener listner = new UploadProgressListener();
195
- listner.setFileName(localFilePath);
196
- insert.getMediaHttpUploader()
197
- .setProgressListener(listner)
198
- .setDirectUploadEnabled(false);
199
-
200
- try {
201
- jobRef = insert.execute().getJobReference();
202
- }
203
- catch (IllegalStateException ex) {
204
- throw new JobFailedException(ex.getMessage());
205
- }
206
- log.info(String.format("Job executed. job id:[%s] file:[%s]", jobRef.getJobId(), localFilePath));
207
- if (isSkipJobResultCheck) {
208
- log.info(String.format("Skip job status check. job id:[%s]", jobRef.getJobId()));
209
- }
210
- else {
211
- getJobStatusUntilDone(project, jobRef);
212
- }
213
- }
214
-
215
- public void replaceTable(String project, String dataset, String oldTable, String newTable)
216
- throws TimeoutException, JobFailedException, IOException
217
- {
218
- copyTable(project, dataset, newTable, oldTable, false);
219
- }
220
-
221
- public void copyTable(String project, String dataset, String fromTable, String toTable, boolean append)
222
- throws TimeoutException, JobFailedException, IOException
223
- {
224
- log.info(String.format("Copy Job preparing... project:%s dataset:%s from:%s to:%s", project, dataset, fromTable, toTable));
225
-
226
- Job job = new Job();
227
- JobReference jobRef = null;
228
- JobConfiguration jobConfig = new JobConfiguration().setCopy(setCopyConfig(project, dataset, fromTable, toTable, append));
229
- job.setConfiguration(jobConfig);
230
- Insert insert = bigQueryClient.jobs().insert(project, job);
231
- insert.setProjectId(project);
232
- insert.setDisableGZipContent(true);
233
-
234
- try {
235
- jobRef = insert.execute().getJobReference();
236
- }
237
- catch (IllegalStateException ex) {
238
- throw new JobFailedException(ex.getMessage());
239
- }
240
- log.info(String.format("Job executed. job id:[%s]", jobRef.getJobId()));
241
- getJobStatusUntilDone(project, jobRef);
242
- }
243
-
244
- public void deleteTable(String project, String dataset, String table) throws IOException
245
- {
246
- try {
247
- Tables.Delete delete = bigQueryClient.tables().delete(project, dataset, table);
248
- delete.execute();
249
- log.info(String.format("Table deleted. project:%s dataset:%s table:%s", delete.getProjectId(), delete.getDatasetId(), delete.getTableId()));
250
- }
251
- catch (GoogleJsonResponseException ex) {
252
- log.warn(ex.getMessage());
253
- }
254
- }
255
-
256
- private JobConfigurationLoad setLoadConfig(String project, String dataset, String table)
257
- {
258
- JobConfigurationLoad config = new JobConfigurationLoad();
259
- config.setAllowQuotedNewlines(allowQuotedNewlines)
260
- .setEncoding(encoding)
261
- .setMaxBadRecords(maxBadRecords)
262
- .setSourceFormat(sourceFormat)
263
- .setIgnoreUnknownValues(ignoreUnknownValues)
264
- .setDestinationTable(createTableReference(project, dataset, table))
265
- .setWriteDisposition("WRITE_APPEND");
266
-
267
- if (sourceFormat.equals("CSV")) {
268
- config.setFieldDelimiter(String.valueOf(fieldDelimiter));
269
- }
270
- if (autoCreateTable) {
271
- config.setSchema(tableSchema);
272
- config.setCreateDisposition("CREATE_IF_NEEDED");
273
- log.info(String.format("table:[%s] will be create if not exists", table));
274
- }
275
- else {
276
- config.setCreateDisposition("CREATE_NEVER");
277
- }
278
- return config;
279
- }
280
-
281
- private JobConfigurationTableCopy setCopyConfig(String project, String dataset, String fromTable, String toTable, boolean append)
282
- {
283
- JobConfigurationTableCopy config = new JobConfigurationTableCopy();
284
- config.setSourceTable(createTableReference(project, dataset, fromTable))
285
- .setDestinationTable(createTableReference(project, dataset, toTable));
286
-
287
- if (append) {
288
- config.setWriteDisposition("WRITE_APPEND");
289
- }
290
- else {
291
- config.setWriteDisposition("WRITE_TRUNCATE");
292
- }
293
-
294
- return config;
295
- }
296
-
297
- private String createJobId(ImmutableList<String> elements) throws NoSuchAlgorithmException, IOException
298
- {
299
- StringBuilder sb = new StringBuilder();
300
- for (String element : elements) {
301
- sb.append(element);
302
- }
303
-
304
- MessageDigest md = MessageDigest.getInstance("MD5");
305
- byte[] digest = md.digest(new String(sb).getBytes());
306
- String hash = new String(Hex.encodeHex(digest));
307
-
308
- StringBuilder jobId = new StringBuilder();
309
- jobId.append("embulk_job_");
310
- jobId.append(hash);
311
- return jobId.toString();
312
- }
313
-
314
- private TableReference createTableReference(String project, String dataset, String table)
315
- {
316
- return new TableReference()
317
- .setProjectId(project)
318
- .setDatasetId(dataset)
319
- .setTableId(table);
320
- }
321
-
322
- public TableSchema createTableSchema() throws IOException
323
- {
324
- String path = schemaPath.orNull();
325
- File file = new File(path);
326
- FileInputStream stream = null;
327
- try {
328
- stream = new FileInputStream(file);
329
- ObjectMapper mapper = new ObjectMapper();
330
- List<TableFieldSchema> fields = mapper.readValue(stream, new TypeReference<List<TableFieldSchema>>() {});
331
- return new TableSchema().setFields(fields);
332
- }
333
- finally {
334
- if (stream != null) {
335
- stream.close();
336
- }
337
- }
338
- }
339
-
340
- public TableSchema fetchTableSchema() throws IOException
341
- {
342
- String fetchTarget = templateTable.orNull();
343
- log.info(String.format("Fetch table schema from project:%s dataset:%s table:%s", project, dataset, fetchTarget));
344
- Tables tableRequest = bigQueryClient.tables();
345
- Table tableData = tableRequest.get(project, dataset, fetchTarget).execute();
346
- return tableData.getSchema();
347
- }
348
-
349
- public boolean isExistTable(String project, String dataset, String table) throws IOException
350
- {
351
- Tables tableRequest = bigQueryClient.tables();
352
- try {
353
- Table tableData = tableRequest.get(project, dataset, table).execute();
354
- }
355
- catch (GoogleJsonResponseException ex) {
356
- return false;
357
- }
358
- return true;
359
- }
360
-
361
- public void checkConfig() throws IOException
362
- {
363
- if (autoCreateTable) {
364
- if (schemaPath.isPresent()) {
365
- File file = new File(schemaPath.orNull());
366
- if (!file.exists()) {
367
- throw new FileNotFoundException("Can not load schema file.");
368
- }
369
- }
370
- else if (!templateTable.isPresent()) {
371
- throw new FileNotFoundException("schema_file or template_table must be present");
372
- }
373
- }
374
- else {
375
- if (!isExistTable(project, dataset, table)) {
376
- throw new IOException(String.format("table [%s] is not exists", table));
377
- }
378
- }
379
- }
380
-
381
- private String getLocalMd5hash(String filePath) throws NoSuchAlgorithmException, IOException
382
- {
383
- FileInputStream stream = null;
384
- try {
385
- stream = new FileInputStream(filePath);
386
- MessageDigest digest = MessageDigest.getInstance("MD5");
387
-
388
- byte[] bytesBuffer = new byte[1024];
389
- int bytesRead = -1;
390
-
391
- while ((bytesRead = stream.read(bytesBuffer)) != -1) {
392
- digest.update(bytesBuffer, 0, bytesRead);
393
- }
394
- byte[] hashedBytes = digest.digest();
395
-
396
- byte[] encoded = (hashedBytes);
397
- return new String(encoded);
398
- }
399
- finally {
400
- stream.close();
401
- }
402
- }
403
-
404
- private class UploadProgressListener implements MediaHttpUploaderProgressListener
405
- {
406
- private String fileName;
407
-
408
- @Override
409
- public void progressChanged(MediaHttpUploader uploader) throws IOException
410
- {
411
- switch (uploader.getUploadState()) {
412
- case INITIATION_STARTED:
413
- log.info(String.format("Upload start [%s]", fileName));
414
- break;
415
- case INITIATION_COMPLETE:
416
- //log.info(String.format("Upload initiation completed file [%s]", fileName));
417
- break;
418
- case MEDIA_IN_PROGRESS:
419
- log.debug(String.format("Uploading [%s] progress %3.0f", fileName, uploader.getProgress() * 100) + "%");
420
- break;
421
- case MEDIA_COMPLETE:
422
- log.info(String.format("Upload completed [%s]", fileName));
423
- }
424
- }
425
-
426
- public void setFileName(String fileName)
427
- {
428
- this.fileName = fileName;
429
- }
430
- }
431
-
432
- public static class Builder
433
- {
434
- private final String authMethod;
435
- private Optional<String> serviceAccountEmail;
436
- private Optional<String> p12KeyFilePath;
437
- private Optional<String> jsonKeyFilePath;
438
- private String applicationName;
439
- private String project;
440
- private String dataset;
441
- private String table;
442
- private boolean autoCreateTable;
443
- private Optional<String> schemaPath;
444
- private Optional<String> templateTable;
445
- private String sourceFormat;
446
- private String fieldDelimiter;
447
- private int maxBadRecords;
448
- private String encoding;
449
- private boolean preventDuplicateInsert;
450
- private int jobStatusMaxPollingTime;
451
- private int jobStatusPollingInterval;
452
- private boolean isSkipJobResultCheck;
453
- private boolean ignoreUnknownValues;
454
- private boolean allowQuotedNewlines;
455
-
456
- public Builder(String authMethod, Optional<String> serviceAccountEmail, Optional<String> p12KeyFilePath,
457
- Optional<String> jsonKeyFilePath, String applicationName)
458
- {
459
- this.authMethod = authMethod;
460
- this.serviceAccountEmail = serviceAccountEmail;
461
- this.p12KeyFilePath = p12KeyFilePath;
462
- this.jsonKeyFilePath = jsonKeyFilePath;
463
- this.applicationName = applicationName;
464
- }
465
-
466
- public Builder setProject(String project)
467
- {
468
- this.project = project;
469
- return this;
470
- }
471
-
472
- public Builder setDataset(String dataset)
473
- {
474
- this.dataset = dataset;
475
- return this;
476
- }
477
-
478
- public Builder setTable(String table)
479
- {
480
- this.table = table;
481
- return this;
482
- }
483
-
484
- public Builder setAutoCreateTable(boolean autoCreateTable)
485
- {
486
- this.autoCreateTable = autoCreateTable;
487
- return this;
488
- }
489
-
490
- public Builder setSchemaPath(Optional<String> schemaPath)
491
- {
492
- this.schemaPath = schemaPath;
493
- return this;
494
- }
495
-
496
- public Builder setTemplateTable(Optional<String> templateTable)
497
- {
498
- this.templateTable = templateTable;
499
- return this;
500
- }
501
-
502
- public Builder setSourceFormat(String sourceFormat)
503
- {
504
- this.sourceFormat = sourceFormat;
505
- return this;
506
- }
507
-
508
- public Builder setFieldDelimiter(String fieldDelimiter)
509
- {
510
- this.fieldDelimiter = fieldDelimiter;
511
- return this;
512
- }
513
-
514
- public Builder setMaxBadRecords(int maxBadRecords)
515
- {
516
- this.maxBadRecords = maxBadRecords;
517
- return this;
518
- }
519
-
520
- public Builder setEncoding(String encoding)
521
- {
522
- this.encoding = encoding;
523
- return this;
524
- }
525
-
526
- public Builder setPreventDuplicateInsert(boolean preventDuplicateInsert)
527
- {
528
- this.preventDuplicateInsert = preventDuplicateInsert;
529
- return this;
530
- }
531
-
532
- public Builder setJobStatusMaxPollingTime(int jobStatusMaxPollingTime)
533
- {
534
- this.jobStatusMaxPollingTime = jobStatusMaxPollingTime;
535
- return this;
536
- }
537
-
538
- public Builder setJobStatusPollingInterval(int jobStatusPollingInterval)
539
- {
540
- this.jobStatusPollingInterval = jobStatusPollingInterval;
541
- return this;
542
- }
543
-
544
- public Builder setIsSkipJobResultCheck(boolean isSkipJobResultCheck)
545
- {
546
- this.isSkipJobResultCheck = isSkipJobResultCheck;
547
- return this;
548
- }
549
-
550
- public Builder setIgnoreUnknownValues(boolean ignoreUnknownValues)
551
- {
552
- this.ignoreUnknownValues = ignoreUnknownValues;
553
- return this;
554
- }
555
-
556
- public Builder setAllowQuotedNewlines(boolean allowQuotedNewlines)
557
- {
558
- this.allowQuotedNewlines = allowQuotedNewlines;
559
- return this;
560
- }
561
-
562
- public BigqueryWriter build() throws IOException, GeneralSecurityException
563
- {
564
- return new BigqueryWriter(this);
565
- }
566
- }
567
-
568
- public class JobFailedException extends RuntimeException
569
- {
570
- public JobFailedException(String message)
571
- {
572
- super(message);
573
- }
574
- }
575
- }