Repository: googleapis/google-cloud-go
Pull request #5287 (2022-01-06 00:25:46)

feat(bigquery): support null marker for csv in external data config
It appears https://b.corp.google.com/issues/140188641 was resolved, but the issue was never marked as such.  Closes out https://github.com/googleapis/google-cloud-go/issues/1888 which has been blocked on backend.


Patch:
diff --git a/bigquery/external.go b/bigquery/external.go
index 1083a19904..afe255660d 100644
--- a/bigquery/external.go
+++ b/bigquery/external.go
@@ -219,6 +219,10 @@ type CSVOptions struct {
 	// The number of rows at the top of a CSV file that BigQuery will skip when
 	// reading data.
 	SkipLeadingRows int64
+
+	// An optional custom string that will represent a NULL
+	// value in CSV import data.
+	NullMarker string
 }
 
 func (o *CSVOptions) populateExternalDataConfig(c *bq.ExternalDataConfiguration) {
@@ -229,6 +233,7 @@ func (o *CSVOptions) populateExternalDataConfig(c *bq.ExternalDataConfiguration)
 		FieldDelimiter:      o.FieldDelimiter,
 		Quote:               o.quote(),
 		SkipLeadingRows:     o.SkipLeadingRows,
+		NullMarker:          o.NullMarker,
 	}
 }
 
@@ -260,6 +265,7 @@ func bqToCSVOptions(q *bq.CsvOptions) *CSVOptions {
 		Encoding:            Encoding(q.Encoding),
 		FieldDelimiter:      q.FieldDelimiter,
 		SkipLeadingRows:     q.SkipLeadingRows,
+		NullMarker:          q.NullMarker,
 	}
 	o.setQuote(q.Quote)
 	return o
diff --git a/bigquery/file.go b/bigquery/file.go
index cb404588be..44eab5dc07 100644
--- a/bigquery/file.go
+++ b/bigquery/file.go
@@ -92,6 +92,7 @@ func (fc *FileConfig) populateLoadConfig(conf *bq.JobConfigurationLoad) {
 	conf.FieldDelimiter = fc.FieldDelimiter
 	conf.IgnoreUnknownValues = fc.IgnoreUnknownValues
 	conf.MaxBadRecords = fc.MaxBadRecords
+	conf.NullMarker = fc.NullMarker
 	if fc.Schema != nil {
 		conf.Schema = fc.Schema.toBQ()
 	}
@@ -118,6 +119,7 @@ func bqPopulateFileConfig(conf *bq.JobConfigurationLoad, fc *FileConfig) {
 	fc.AllowQuotedNewlines = conf.AllowQuotedNewlines
 	fc.Encoding = Encoding(conf.Encoding)
 	fc.FieldDelimiter = conf.FieldDelimiter
+	fc.CSVOptions.NullMarker = conf.NullMarker
 	fc.CSVOptions.setQuote(conf.Quote)
 }
 


Test patch:
diff --git a/bigquery/external_test.go b/bigquery/external_test.go
index 4a8b3ec7d6..6eb930d74b 100644
--- a/bigquery/external_test.go
+++ b/bigquery/external_test.go
@@ -39,6 +39,7 @@ func TestExternalDataConfig(t *testing.T) {
 				FieldDelimiter:      "f",
 				Quote:               "q",
 				SkipLeadingRows:     3,
+				NullMarker:          "marker",
 			},
 		},
 		{
diff --git a/bigquery/file_test.go b/bigquery/file_test.go
index bb55d8abea..e57633f363 100644
--- a/bigquery/file_test.go
+++ b/bigquery/file_test.go
@@ -39,6 +39,7 @@ var (
 			AllowJaggedRows:     true,
 			AllowQuotedNewlines: true,
 			Encoding:            UTF_8,
+			NullMarker:          "marker",
 		},
 	}
 )
@@ -71,6 +72,7 @@ func TestFileConfigPopulateLoadConfig(t *testing.T) {
 				Encoding:            "UTF-8",
 				MaxBadRecords:       7,
 				IgnoreUnknownValues: true,
+				NullMarker:          "marker",
 				Schema: &bq.TableSchema{
 					Fields: []*bq.TableFieldSchema{
 						bqStringFieldSchema(),
@@ -154,6 +156,7 @@ func TestFileConfigPopulateExternalDataConfig(t *testing.T) {
 					FieldDelimiter:      "\t",
 					Quote:               &hyphen,
 					SkipLeadingRows:     8,
+					NullMarker:          "marker",
 				},
 			},
 		},