all: remove 1.6, 1.7, 1.8 build flags and split files
Since we no longer support 1.8 and below, all of this is unnecessary.
Change-Id: Id47b97efcf6a5c0d40fb67c8fbd999a452de8f2f
Reviewed-on: https://code-review.googlesource.com/c/35411
Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Eno Compton <enocom@google.com>
diff --git a/bigquery/oc_test.go b/bigquery/oc_test.go
index 07d1b71..de85173 100644
--- a/bigquery/oc_test.go
+++ b/bigquery/oc_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package bigquery
import (
diff --git a/bigtable/not_go18.go b/bigtable/not_go18.go
deleted file mode 100644
index 17109ea..0000000
--- a/bigtable/not_go18.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !go1.8
-
-package bigtable
-
-import (
- "context"
-
- "google.golang.org/api/option"
-)
-
-// OpenCensus only supports go 1.8 and higher.
-
-func openCensusOptions() []option.ClientOption { return nil }
-
-func traceStartSpan(ctx context.Context, _ string) context.Context {
- return ctx
-}
-
-func traceEndSpan(context.Context, error) {
-}
-
-func tracePrintf(context.Context, map[string]interface{}, string, ...interface{}) {
-}
diff --git a/bigtable/go18.go b/bigtable/trace.go
similarity index 84%
rename from bigtable/go18.go
rename to bigtable/trace.go
index 13f8f66..6c579b1 100644
--- a/bigtable/go18.go
+++ b/bigtable/trace.go
@@ -12,26 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package bigtable
import (
"context"
"fmt"
- "go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/trace"
- "google.golang.org/api/option"
- "google.golang.org/grpc"
)
-func openCensusOptions() []option.ClientOption {
- return []option.ClientOption{
- option.WithGRPCDialOption(grpc.WithStatsHandler(&ocgrpc.ClientHandler{})),
- }
-}
-
func traceStartSpan(ctx context.Context, name string) context.Context {
ctx, _ = trace.StartSpan(ctx, name)
return ctx
diff --git a/datastore/oc_test.go b/datastore/oc_test.go
index 836c271..be1e5a4 100644
--- a/datastore/oc_test.go
+++ b/datastore/oc_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package datastore
import (
diff --git a/httpreplay/cmd/httpr/httpr.go b/httpreplay/cmd/httpr/httpr.go
index eb5583c..cc734c4 100644
--- a/httpreplay/cmd/httpr/httpr.go
+++ b/httpreplay/cmd/httpr/httpr.go
@@ -18,8 +18,6 @@
// To get the CA certificate of the proxy, issue a GET to http://localhost:CP/authority.cer, where
// CP is the control port.
-// +build go1.8
-
package main
import (
diff --git a/httpreplay/cmd/httpr/integration_test.go b/httpreplay/cmd/httpr/integration_test.go
index 7d370b4..bce29e6 100644
--- a/httpreplay/cmd/httpr/integration_test.go
+++ b/httpreplay/cmd/httpr/integration_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package main_test
import (
diff --git a/httpreplay/httpreplay.go b/httpreplay/httpreplay.go
index 86de2c0..7c4e9e3 100644
--- a/httpreplay/httpreplay.go
+++ b/httpreplay/httpreplay.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
// Package httpreplay provides an API for recording and replaying traffic
// from HTTP-based Google API clients.
//
diff --git a/httpreplay/httpreplay_not18.go b/httpreplay/httpreplay_not18.go
deleted file mode 100644
index 3fbbf65..0000000
--- a/httpreplay/httpreplay_not18.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2018 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !go1.8
-
-// httpreplay is available in go1.8 and forward. This file exists only for 1.6 and 1.7 to
-// compile, since every package must have some buildable file else go test ./... fails.
-package httpreplay
-
-import (
- "context"
- "net/http"
-
- "google.golang.org/api/option"
-)
-
-// Supported reports whether httpreplay is supported in the current version of Go.
-// For Go 1.7 and below, the answer is false.
-func Supported() bool { return false }
-
-type (
- Recorder struct{}
-
- Replayer struct{}
-)
-
-func NewRecorder(string, []byte) (*Recorder, error) { return nil, nil }
-
-func (*Recorder) Client(context.Context, ...option.ClientOption) (*http.Client, error) {
- return nil, nil
-}
-func (*Recorder) Close() error { return nil }
-
-func NewReplayer(string) (*Replayer, error) { return nil, nil }
-
-func (*Replayer) Initial() []byte { return nil }
-func (*Replayer) IgnoreHeader(string) {}
-func (*Replayer) Client(context.Context) (*http.Client, error) { return nil, nil }
-func (*Replayer) Close() error { return nil }
-
-func DebugHeaders() {}
diff --git a/httpreplay/httpreplay_test.go b/httpreplay/httpreplay_test.go
index 45f7fa5..1fa0f24 100644
--- a/httpreplay/httpreplay_test.go
+++ b/httpreplay/httpreplay_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package httpreplay_test
import (
diff --git a/httpreplay/internal/proxy/debug.go b/httpreplay/internal/proxy/debug.go
index 20acbe9..caf1997 100644
--- a/httpreplay/internal/proxy/debug.go
+++ b/httpreplay/internal/proxy/debug.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package proxy
import (
diff --git a/httpreplay/internal/proxy/log.go b/httpreplay/internal/proxy/log.go
index 3eec478..d1759ce 100644
--- a/httpreplay/internal/proxy/log.go
+++ b/httpreplay/internal/proxy/log.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package proxy
import (
diff --git a/httpreplay/internal/proxy/log_test.go b/httpreplay/internal/proxy/log_test.go
index f1de685..327227c 100644
--- a/httpreplay/internal/proxy/log_test.go
+++ b/httpreplay/internal/proxy/log_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package proxy
import (
diff --git a/httpreplay/internal/proxy/record.go b/httpreplay/internal/proxy/record.go
index b3b76c0..57eacaf 100644
--- a/httpreplay/internal/proxy/record.go
+++ b/httpreplay/internal/proxy/record.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
// Package proxy provides a record/replay HTTP proxy. It is designed to support
// both an in-memory API (cloud.google.com/go/httpreplay) and a standalone server
// (cloud.google.com/go/httpreplay/cmd/httpr).
diff --git a/httpreplay/internal/proxy/replay.go b/httpreplay/internal/proxy/replay.go
index b802057..e785c9a 100644
--- a/httpreplay/internal/proxy/replay.go
+++ b/httpreplay/internal/proxy/replay.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package proxy
import (
diff --git a/httpreplay/internal/proxy/replay_test.go b/httpreplay/internal/proxy/replay_test.go
index 0d0cb6e..72ce582 100644
--- a/httpreplay/internal/proxy/replay_test.go
+++ b/httpreplay/internal/proxy/replay_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package proxy
import (
diff --git a/internal/btree/benchmarks_test.go b/internal/btree/benchmarks_test.go
index cc3da57..4910cab 100644
--- a/internal/btree/benchmarks_test.go
+++ b/internal/btree/benchmarks_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.7
-
package btree
import (
diff --git a/internal/testutil/go18.go b/internal/testutil/trace.go
similarity index 98%
rename from internal/testutil/go18.go
rename to internal/testutil/trace.go
index 5d7e027..b0a7b77 100644
--- a/internal/testutil/go18.go
+++ b/internal/testutil/trace.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package testutil
import (
diff --git a/internal/trace/not_go18.go b/internal/trace/not_go18.go
deleted file mode 100644
index 7e681b6..0000000
--- a/internal/trace/not_go18.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2018 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !go1.8
-
-package trace
-
-import (
- "context"
-)
-
-// OpenCensus only supports go 1.8 and higher.
-
-func StartSpan(ctx context.Context, _ string) context.Context {
- return ctx
-}
-
-func EndSpan(context.Context, error) {
-}
diff --git a/internal/trace/go18.go b/internal/trace/trace.go
similarity index 99%
rename from internal/trace/go18.go
rename to internal/trace/trace.go
index 3a100a3..95c7821 100644
--- a/internal/trace/go18.go
+++ b/internal/trace/trace.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package trace
import (
diff --git a/internal/trace/go18_test.go b/internal/trace/trace_test.go
similarity index 98%
rename from internal/trace/go18_test.go
rename to internal/trace/trace_test.go
index f907270..2af9fb8 100644
--- a/internal/trace/go18_test.go
+++ b/internal/trace/trace_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package trace
import (
diff --git a/logging/examples_go18_test.go b/logging/examples_go18_test.go
deleted file mode 100644
index 778649c..0000000
--- a/logging/examples_go18_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2016 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build go1.8
-
-package logging_test
-
-import (
- "context"
-
- "cloud.google.com/go/logging"
- "go.opencensus.io/trace"
-)
-
-// This example shows how to create a Logger that disables OpenCensus tracing of the
-// WriteLogEntries RPC.
-func ExampleContextFunc() {
- ctx := context.Background()
- client, err := logging.NewClient(ctx, "my-project")
- if err != nil {
- // TODO: Handle error.
- }
- lg := client.Logger("logID", logging.ContextFunc(func() (context.Context, func()) {
- ctx, span := trace.StartSpan(context.Background(), "this span will not be exported",
- trace.WithSampler(trace.NeverSample()))
- return ctx, span.End
- }))
- _ = lg // TODO: Use lg
-}
diff --git a/logging/examples_test.go b/logging/examples_test.go
index 44a8c82..b9623ee 100644
--- a/logging/examples_test.go
+++ b/logging/examples_test.go
@@ -21,6 +21,7 @@
"os"
"cloud.google.com/go/logging"
+ "go.opencensus.io/trace"
)
func ExampleNewClient() {
@@ -164,3 +165,19 @@
fmt.Println(sev)
// Output: Alert
}
+
+// This example shows how to create a Logger that disables OpenCensus tracing of the
+// WriteLogEntries RPC.
+func ExampleContextFunc() {
+ ctx := context.Background()
+ client, err := logging.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ lg := client.Logger("logID", logging.ContextFunc(func() (context.Context, func()) {
+ ctx, span := trace.StartSpan(context.Background(), "this span will not be exported",
+ trace.WithSampler(trace.NeverSample()))
+ return ctx, span.End
+ }))
+ _ = lg // TODO: Use lg
+}
diff --git a/profiler/mutex.go b/profiler/mutex.go
index 93512fa..c432adb 100644
--- a/profiler/mutex.go
+++ b/profiler/mutex.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package profiler
import "runtime"
diff --git a/profiler/mutex_go17.go b/profiler/mutex_go17.go
deleted file mode 100644
index 5b9ae9c..0000000
--- a/profiler/mutex_go17.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2017 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !go1.8
-
-package profiler
-
-func enableMutexProfiling() bool {
- return false
-}
diff --git a/profiler/proftest/proftest.go b/profiler/proftest/proftest.go
index 561414c..b103dd5 100644
--- a/profiler/proftest/proftest.go
+++ b/profiler/proftest/proftest.go
@@ -15,11 +15,6 @@
// Package proftest contains test helpers for profiler agent integration tests.
// This package is experimental.
-// golang.org/x/build/kubernetes/dialer.go imports "context" package (rather
-// than "context") and that does not exist in Go 1.6 or
-// earlier.
-// +build go1.7
-
package proftest
import (
diff --git a/pubsub/not_go18.go b/pubsub/not_go18.go
deleted file mode 100644
index dd90331..0000000
--- a/pubsub/not_go18.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2018 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !go1.8
-
-package pubsub
-
-import (
- "context"
-
- "google.golang.org/api/option"
-)
-
-// OpenCensus only supports go 1.8 and higher.
-
-func openCensusOptions() []option.ClientOption { return nil }
-
-func withSubscriptionKey(ctx context.Context, _ string) context.Context {
- return ctx
-}
-
-type dummy struct{}
-
-var (
- // Not supported below Go 1.8.
- PullCount dummy
- // Not supported below Go 1.8.
- AckCount dummy
- // Not supported below Go 1.8.
- NackCount dummy
- // Not supported below Go 1.8.
- ModAckCount dummy
- // Not supported below Go 1.8.
- ModAckTimeoutCount dummy
- // Not supported below Go 1.8.
- StreamOpenCount dummy
- // Not supported below Go 1.8.
- StreamRetryCount dummy
- // Not supported below Go 1.8.
- StreamRequestCount dummy
- // Not supported below Go 1.8.
- StreamResponseCount dummy
-)
-
-func recordStat(context.Context, dummy, int64) {
-}
diff --git a/pubsub/go18.go b/pubsub/trace.go
similarity index 99%
rename from pubsub/go18.go
rename to pubsub/trace.go
index 9396cf1..06965c2 100644
--- a/pubsub/go18.go
+++ b/pubsub/trace.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package pubsub
import (
diff --git a/spanner/go17.go b/spanner/go17.go
deleted file mode 100644
index f42419f..0000000
--- a/spanner/go17.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build go1.7
-
-package spanner
-
-import "reflect"
-
-func structTagLookup(tag reflect.StructTag, key string) (string, bool) {
- return tag.Lookup(key)
-}
diff --git a/spanner/go17_test.go b/spanner/go17_test.go
deleted file mode 100644
index 325349a..0000000
--- a/spanner/go17_test.go
+++ /dev/null
@@ -1,466 +0,0 @@
-// Copyright 2018 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build go1.7
-
-package spanner
-
-import (
- "context"
- "reflect"
- "testing"
- "time"
-
- "cloud.google.com/go/civil"
- proto "github.com/golang/protobuf/proto"
- proto3 "github.com/golang/protobuf/ptypes/struct"
- sppb "google.golang.org/genproto/googleapis/spanner/v1"
-)
-
-func TestEncodeStructValueDynamicStructs(t *testing.T) {
- dynStructType := reflect.StructOf([]reflect.StructField{
- {Name: "A", Type: reflect.TypeOf(0), Tag: `spanner:"a"`},
- {Name: "B", Type: reflect.TypeOf(""), Tag: `spanner:"b"`},
- })
- dynNullableStructType := reflect.PtrTo(dynStructType)
- dynStructArrType := reflect.SliceOf(dynStructType)
- dynNullableStructArrType := reflect.SliceOf(dynNullableStructType)
-
- dynStructValue := reflect.New(dynStructType)
- dynStructValue.Elem().Field(0).SetInt(10)
- dynStructValue.Elem().Field(1).SetString("abc")
-
- dynStructArrValue := reflect.MakeSlice(dynNullableStructArrType, 2, 2)
- dynStructArrValue.Index(0).Set(reflect.Zero(dynNullableStructType))
- dynStructArrValue.Index(1).Set(dynStructValue)
-
- structProtoType := structType(
- mkField("a", intType()),
- mkField("b", stringType()))
-
- arrProtoType := listType(structProtoType)
-
- for _, test := range []encodeTest{
- {
- "Dynanic non-NULL struct value.",
- dynStructValue.Elem().Interface(),
- listProto(intProto(10), stringProto("abc")),
- structProtoType,
- },
- {
- "Dynanic NULL struct value.",
- reflect.Zero(dynNullableStructType).Interface(),
- nullProto(),
- structProtoType,
- },
- {
- "Empty array of dynamic structs.",
- reflect.MakeSlice(dynStructArrType, 0, 0).Interface(),
- listProto([]*proto3.Value{}...),
- arrProtoType,
- },
- {
- "NULL array of non-NULL-able dynamic structs.",
- reflect.Zero(dynStructArrType).Interface(),
- nullProto(),
- arrProtoType,
- },
- {
- "NULL array of NULL-able(nil) dynamic structs.",
- reflect.Zero(dynNullableStructArrType).Interface(),
- nullProto(),
- arrProtoType,
- },
- {
- "Array containing NULL(nil) dynamic-typed struct elements.",
- dynStructArrValue.Interface(),
- listProto(
- nullProto(),
- listProto(intProto(10), stringProto("abc"))),
- arrProtoType,
- },
- } {
- encodeStructValue(test, t)
- }
-}
-
-func TestEncodeStructValueEmptyStruct(t *testing.T) {
- emptyListValue := listProto([]*proto3.Value{}...)
- emptyStructType := structType([]*sppb.StructType_Field{}...)
- emptyStruct := struct{}{}
- nullEmptyStruct := (*struct{})(nil)
-
- dynamicEmptyStructType := reflect.StructOf(make([]reflect.StructField, 0, 0))
- dynamicStructArrType := reflect.SliceOf(reflect.PtrTo((dynamicEmptyStructType)))
-
- dynamicEmptyStruct := reflect.New(dynamicEmptyStructType)
- dynamicNullEmptyStruct := reflect.Zero(reflect.PtrTo(dynamicEmptyStructType))
-
- dynamicStructArrValue := reflect.MakeSlice(dynamicStructArrType, 2, 2)
- dynamicStructArrValue.Index(0).Set(dynamicNullEmptyStruct)
- dynamicStructArrValue.Index(1).Set(dynamicEmptyStruct)
-
- for _, test := range []encodeTest{
- {
- "Go empty struct.",
- emptyStruct,
- emptyListValue,
- emptyStructType,
- },
- {
- "Dynamic empty struct.",
- dynamicEmptyStruct.Interface(),
- emptyListValue,
- emptyStructType,
- },
- {
- "Go NULL empty struct.",
- nullEmptyStruct,
- nullProto(),
- emptyStructType,
- },
- {
- "Dynamic NULL empty struct.",
- dynamicNullEmptyStruct.Interface(),
- nullProto(),
- emptyStructType,
- },
- {
- "Non-empty array of dynamic NULL and non-NULL empty structs.",
- dynamicStructArrValue.Interface(),
- listProto(nullProto(), emptyListValue),
- listType(emptyStructType),
- },
- {
- "Non-empty array of nullable empty structs.",
- []*struct{}{nullEmptyStruct, &emptyStruct},
- listProto(nullProto(), emptyListValue),
- listType(emptyStructType),
- },
- {
- "Empty array of empty struct.",
- []struct{}{},
- emptyListValue,
- listType(emptyStructType),
- },
- {
- "Null array of empty structs.",
- []struct{}(nil),
- nullProto(),
- listType(emptyStructType),
- },
- } {
- encodeStructValue(test, t)
- }
-}
-
-func TestEncodeStructValueMixedStructTypes(t *testing.T) {
- type staticStruct struct {
- F int `spanner:"fStatic"`
- }
- s1 := staticStruct{10}
- s2 := (*staticStruct)(nil)
-
- var f float64
- dynStructType := reflect.StructOf([]reflect.StructField{
- {Name: "A", Type: reflect.TypeOf(f), Tag: `spanner:"fDynamic"`},
- })
- s3 := reflect.New(dynStructType)
- s3.Elem().Field(0).SetFloat(3.14)
-
- for _, test := range []encodeTest{
- {
- "'struct' with static and dynamic *struct, []*struct, []struct fields",
- struct {
- A []staticStruct
- B []*staticStruct
- C interface{}
- }{
- []staticStruct{s1, s1},
- []*staticStruct{&s1, s2},
- s3.Interface(),
- },
- listProto(
- listProto(listProto(intProto(10)), listProto(intProto(10))),
- listProto(listProto(intProto(10)), nullProto()),
- listProto(floatProto(3.14))),
- structType(
- mkField("A", listType(structType(mkField("fStatic", intType())))),
- mkField("B", listType(structType(mkField("fStatic", intType())))),
- mkField("C", structType(mkField("fDynamic", floatType())))),
- },
- } {
- encodeStructValue(test, t)
- }
-}
-
-func TestBindParamsDynamic(t *testing.T) {
- // Verify Statement.bindParams generates correct values and types.
- st := Statement{
- SQL: "SELECT id from t_foo WHERE col = @var",
- Params: map[string]interface{}{"var": nil},
- }
- want := &sppb.ExecuteSqlRequest{
- Params: &proto3.Struct{
- Fields: map[string]*proto3.Value{"var": nil},
- },
- ParamTypes: map[string]*sppb.Type{"var": nil},
- }
- var (
- t1, _ = time.Parse(time.RFC3339Nano, "2016-11-15T15:04:05.999999999Z")
- // Boundaries
- t2, _ = time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00.000000000Z")
- )
- dynamicStructType := reflect.StructOf([]reflect.StructField{
- {Name: "A", Type: reflect.TypeOf(t1), Tag: `spanner:"field"`},
- {Name: "B", Type: reflect.TypeOf(3.14), Tag: `spanner:""`},
- })
- dynamicStructArrType := reflect.SliceOf(reflect.PtrTo(dynamicStructType))
- dynamicEmptyStructType := reflect.StructOf(make([]reflect.StructField, 0, 0))
-
- dynamicStructTypeProto := structType(
- mkField("field", timeType()),
- mkField("", floatType()))
-
- s3 := reflect.New(dynamicStructType)
- s3.Elem().Field(0).Set(reflect.ValueOf(t1))
- s3.Elem().Field(1).SetFloat(1.4)
-
- s4 := reflect.New(dynamicStructType)
- s4.Elem().Field(0).Set(reflect.ValueOf(t2))
- s4.Elem().Field(1).SetFloat(-13.3)
-
- dynamicStructArrayVal := reflect.MakeSlice(dynamicStructArrType, 2, 2)
- dynamicStructArrayVal.Index(0).Set(s3)
- dynamicStructArrayVal.Index(1).Set(s4)
-
- for i, test := range []struct {
- val interface{}
- wantField *proto3.Value
- wantType *sppb.Type
- }{
- {
- s3.Interface(),
- listProto(timeProto(t1), floatProto(1.4)),
- structType(
- mkField("field", timeType()),
- mkField("", floatType())),
- },
- {
- reflect.Zero(reflect.PtrTo(dynamicEmptyStructType)).Interface(),
- nullProto(),
- structType([]*sppb.StructType_Field{}...),
- },
- {
- dynamicStructArrayVal.Interface(),
- listProto(
- listProto(timeProto(t1), floatProto(1.4)),
- listProto(timeProto(t2), floatProto(-13.3))),
- listType(dynamicStructTypeProto),
- },
- {
- []*struct {
- F1 time.Time `spanner:"field"`
- F2 float64 `spanner:""`
- }{
- nil,
- {t1, 1.4},
- },
- listProto(
- nullProto(),
- listProto(timeProto(t1), floatProto(1.4))),
- listType(dynamicStructTypeProto),
- },
- } {
- st.Params["var"] = test.val
- want.Params.Fields["var"] = test.wantField
- want.ParamTypes["var"] = test.wantType
- got := &sppb.ExecuteSqlRequest{}
- if err := st.bindParams(got); err != nil || !proto.Equal(got, want) {
- // handle NaN
- if test.wantType.Code == floatType().Code && proto.MarshalTextString(got) == proto.MarshalTextString(want) {
- continue
- }
- t.Errorf("#%d: bind result: \n(%v, %v)\nwant\n(%v, %v)\n", i, got, err, want, nil)
- }
- }
-}
-
-func TestStructParametersBind(t *testing.T) {
- t.Parallel()
- ctx := context.Background()
- client, _, cleanup := prepare(ctx, t, nil)
- defer cleanup()
-
- type tRow []interface{}
- type tRows []struct{ trow tRow }
-
- type allFields struct {
- Stringf string
- Intf int
- Boolf bool
- Floatf float64
- Bytef []byte
- Timef time.Time
- Datef civil.Date
- }
- allColumns := []string{
- "Stringf",
- "Intf",
- "Boolf",
- "Floatf",
- "Bytef",
- "Timef",
- "Datef",
- }
- s1 := allFields{"abc", 300, false, 3.45, []byte("foo"), t1, d1}
- s2 := allFields{"def", -300, false, -3.45, []byte("bar"), t2, d2}
-
- dynamicStructType := reflect.StructOf([]reflect.StructField{
- {Name: "A", Type: reflect.TypeOf(t1), Tag: `spanner:"ff1"`},
- })
- s3 := reflect.New(dynamicStructType)
- s3.Elem().Field(0).Set(reflect.ValueOf(t1))
-
- for i, test := range []struct {
- param interface{}
- sql string
- cols []string
- trows tRows
- }{
- // Struct value.
- {
- s1,
- "SELECT" +
- " @p.Stringf," +
- " @p.Intf," +
- " @p.Boolf," +
- " @p.Floatf," +
- " @p.Bytef," +
- " @p.Timef," +
- " @p.Datef",
- allColumns,
- tRows{
- {tRow{"abc", 300, false, 3.45, []byte("foo"), t1, d1}},
- },
- },
- // Array of struct value.
- {
- []allFields{s1, s2},
- "SELECT * FROM UNNEST(@p)",
- allColumns,
- tRows{
- {tRow{"abc", 300, false, 3.45, []byte("foo"), t1, d1}},
- {tRow{"def", -300, false, -3.45, []byte("bar"), t2, d2}},
- },
- },
- // Null struct.
- {
- (*allFields)(nil),
- "SELECT @p IS NULL",
- []string{""},
- tRows{
- {tRow{true}},
- },
- },
- // Null Array of struct.
- {
- []allFields(nil),
- "SELECT @p IS NULL",
- []string{""},
- tRows{
- {tRow{true}},
- },
- },
- // Empty struct.
- {
- struct{}{},
- "SELECT @p IS NULL ",
- []string{""},
- tRows{
- {tRow{false}},
- },
- },
- // Empty array of struct.
- {
- []allFields{},
- "SELECT * FROM UNNEST(@p) ",
- allColumns,
- tRows{},
- },
- // Struct with duplicate fields.
- {
- struct {
- A int `spanner:"field"`
- B int `spanner:"field"`
- }{10, 20},
- "SELECT * FROM UNNEST([@p]) ",
- []string{"field", "field"},
- tRows{
- {tRow{10, 20}},
- },
- },
- // Struct with unnamed fields.
- {
- struct {
- A string `spanner:""`
- }{"hello"},
- "SELECT * FROM UNNEST([@p]) ",
- []string{""},
- tRows{
- {tRow{"hello"}},
- },
- },
- // Mixed struct.
- {
- struct {
- DynamicStructField interface{} `spanner:"f1"`
- ArrayStructField []*allFields `spanner:"f2"`
- }{
- DynamicStructField: s3.Interface(),
- ArrayStructField: []*allFields{nil},
- },
- "SELECT @p.f1.ff1, ARRAY_LENGTH(@p.f2), @p.f2[OFFSET(0)] IS NULL ",
- []string{"ff1", "", ""},
- tRows{
- {tRow{t1, 1, true}},
- },
- },
- } {
- iter := client.Single().Query(ctx, Statement{
- SQL: test.sql,
- Params: map[string]interface{}{"p": test.param},
- })
- var gotRows []*Row
- err := iter.Do(func(r *Row) error {
- gotRows = append(gotRows, r)
- return nil
- })
- if err != nil {
- t.Errorf("Failed to execute test case %d, error: %v", i, err)
- }
-
- var wantRows []*Row
- for j, row := range test.trows {
- r, err := NewRow(test.cols, row.trow)
- if err != nil {
- t.Errorf("Invalid row %d in test case %d", j, i)
- }
- wantRows = append(wantRows, r)
- }
- if !testEqual(gotRows, wantRows) {
- t.Errorf("%d: Want result %v, got result %v", i, wantRows, gotRows)
- }
- }
-}
diff --git a/spanner/not_go17.go b/spanner/not_go17.go
deleted file mode 100644
index 19b2c4a..0000000
--- a/spanner/not_go17.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2018 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !go1.7
-
-package spanner
-
-import (
- "reflect"
- "strconv"
-)
-
-func structTagLookup(tag reflect.StructTag, key string) (string, bool) {
- // from go1.10.2 implementation of StructTag.Lookup.
- for tag != "" {
- // Skip leading space.
- i := 0
- for i < len(tag) && tag[i] == ' ' {
- i++
- }
- tag = tag[i:]
- if tag == "" {
- break
- }
-
- // Scan to colon. A space, a quote or a control character is a syntax error.
- // Strictly speaking, control chars include the range [0x7f, 0x9f], not just
- // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
- // as it is simpler to inspect the tag's bytes than the tag's runes.
- i = 0
- for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
- i++
- }
- if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
- break
- }
- name := string(tag[:i])
- tag = tag[i+1:]
-
- // Scan quoted string to find value.
- i = 1
- for i < len(tag) && tag[i] != '"' {
- if tag[i] == '\\' {
- i++
- }
- i++
- }
- if i >= len(tag) {
- break
- }
- qvalue := string(tag[:i+1])
- tag = tag[i+1:]
-
- if key == name {
- value, err := strconv.Unquote(qvalue)
- if err != nil {
- break
- }
- return value, true
- }
- }
- return "", false
-}
diff --git a/spanner/not_go18.go b/spanner/not_go18.go
deleted file mode 100644
index 41c3481..0000000
--- a/spanner/not_go18.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !go1.8
-
-package spanner
-
-import "context"
-
-// OpenCensus only supports go 1.8 and higher.
-
-func traceStartSpan(ctx context.Context, _ string) context.Context {
- return ctx
-}
-
-func traceEndSpan(context.Context, error) {
-}
-
-func tracePrintf(context.Context, map[string]interface{}, string, ...interface{}) {
-}
-
-type dummy struct{}
-
-// Not supported below Go 1.8.
-var OpenSessionCount dummy
-
-func recordStat(context.Context, dummy, int64) {
-}
diff --git a/spanner/oc_test.go b/spanner/oc_test.go
index dbe93e7..7e95713 100644
--- a/spanner/oc_test.go
+++ b/spanner/oc_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package spanner
import (
diff --git a/spanner/go18.go b/spanner/trace.go
similarity index 98%
rename from spanner/go18.go
rename to spanner/trace.go
index 9f09bf3..6fdbae4 100644
--- a/spanner/go18.go
+++ b/spanner/trace.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package spanner
import (
diff --git a/spanner/value.go b/spanner/value.go
index 1e32a87..8e049d3 100644
--- a/spanner/value.go
+++ b/spanner/value.go
@@ -1487,7 +1487,7 @@
continue
}
- fname, ok := structTagLookup(sf.Tag, "spanner")
+ fname, ok := sf.Tag.Lookup("spanner")
if !ok {
fname = sf.Name
}
diff --git a/spanner/value_benchmarks_test.go b/spanner/value_benchmarks_test.go
index fe09f00..32ea2d7 100644
--- a/spanner/value_benchmarks_test.go
+++ b/spanner/value_benchmarks_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.7
-
package spanner
import (
diff --git a/spanner/value_test.go b/spanner/value_test.go
index 5be8df3..e9ca587 100644
--- a/spanner/value_test.go
+++ b/spanner/value_test.go
@@ -17,12 +17,14 @@
package spanner
import (
+ "context"
"math"
"reflect"
"testing"
"time"
"cloud.google.com/go/civil"
+ proto "github.com/golang/protobuf/proto"
proto3 "github.com/golang/protobuf/ptypes/struct"
sppb "google.golang.org/genproto/googleapis/spanner/v1"
)
@@ -1114,3 +1116,440 @@
}
}
}
+
+func TestEncodeStructValueDynamicStructs(t *testing.T) {
+ dynStructType := reflect.StructOf([]reflect.StructField{
+ {Name: "A", Type: reflect.TypeOf(0), Tag: `spanner:"a"`},
+ {Name: "B", Type: reflect.TypeOf(""), Tag: `spanner:"b"`},
+ })
+ dynNullableStructType := reflect.PtrTo(dynStructType)
+ dynStructArrType := reflect.SliceOf(dynStructType)
+ dynNullableStructArrType := reflect.SliceOf(dynNullableStructType)
+
+ dynStructValue := reflect.New(dynStructType)
+ dynStructValue.Elem().Field(0).SetInt(10)
+ dynStructValue.Elem().Field(1).SetString("abc")
+
+ dynStructArrValue := reflect.MakeSlice(dynNullableStructArrType, 2, 2)
+ dynStructArrValue.Index(0).Set(reflect.Zero(dynNullableStructType))
+ dynStructArrValue.Index(1).Set(dynStructValue)
+
+ structProtoType := structType(
+ mkField("a", intType()),
+ mkField("b", stringType()))
+
+ arrProtoType := listType(structProtoType)
+
+ for _, test := range []encodeTest{
+ {
+ "Dynanic non-NULL struct value.",
+ dynStructValue.Elem().Interface(),
+ listProto(intProto(10), stringProto("abc")),
+ structProtoType,
+ },
+ {
+ "Dynanic NULL struct value.",
+ reflect.Zero(dynNullableStructType).Interface(),
+ nullProto(),
+ structProtoType,
+ },
+ {
+ "Empty array of dynamic structs.",
+ reflect.MakeSlice(dynStructArrType, 0, 0).Interface(),
+ listProto([]*proto3.Value{}...),
+ arrProtoType,
+ },
+ {
+ "NULL array of non-NULL-able dynamic structs.",
+ reflect.Zero(dynStructArrType).Interface(),
+ nullProto(),
+ arrProtoType,
+ },
+ {
+ "NULL array of NULL-able(nil) dynamic structs.",
+ reflect.Zero(dynNullableStructArrType).Interface(),
+ nullProto(),
+ arrProtoType,
+ },
+ {
+ "Array containing NULL(nil) dynamic-typed struct elements.",
+ dynStructArrValue.Interface(),
+ listProto(
+ nullProto(),
+ listProto(intProto(10), stringProto("abc"))),
+ arrProtoType,
+ },
+ } {
+ encodeStructValue(test, t)
+ }
+}
+
+func TestEncodeStructValueEmptyStruct(t *testing.T) {
+ emptyListValue := listProto([]*proto3.Value{}...)
+ emptyStructType := structType([]*sppb.StructType_Field{}...)
+ emptyStruct := struct{}{}
+ nullEmptyStruct := (*struct{})(nil)
+
+ dynamicEmptyStructType := reflect.StructOf(make([]reflect.StructField, 0, 0))
+ dynamicStructArrType := reflect.SliceOf(reflect.PtrTo((dynamicEmptyStructType)))
+
+ dynamicEmptyStruct := reflect.New(dynamicEmptyStructType)
+ dynamicNullEmptyStruct := reflect.Zero(reflect.PtrTo(dynamicEmptyStructType))
+
+ dynamicStructArrValue := reflect.MakeSlice(dynamicStructArrType, 2, 2)
+ dynamicStructArrValue.Index(0).Set(dynamicNullEmptyStruct)
+ dynamicStructArrValue.Index(1).Set(dynamicEmptyStruct)
+
+ for _, test := range []encodeTest{
+ {
+ "Go empty struct.",
+ emptyStruct,
+ emptyListValue,
+ emptyStructType,
+ },
+ {
+ "Dynamic empty struct.",
+ dynamicEmptyStruct.Interface(),
+ emptyListValue,
+ emptyStructType,
+ },
+ {
+ "Go NULL empty struct.",
+ nullEmptyStruct,
+ nullProto(),
+ emptyStructType,
+ },
+ {
+ "Dynamic NULL empty struct.",
+ dynamicNullEmptyStruct.Interface(),
+ nullProto(),
+ emptyStructType,
+ },
+ {
+ "Non-empty array of dynamic NULL and non-NULL empty structs.",
+ dynamicStructArrValue.Interface(),
+ listProto(nullProto(), emptyListValue),
+ listType(emptyStructType),
+ },
+ {
+ "Non-empty array of nullable empty structs.",
+ []*struct{}{nullEmptyStruct, &emptyStruct},
+ listProto(nullProto(), emptyListValue),
+ listType(emptyStructType),
+ },
+ {
+ "Empty array of empty struct.",
+ []struct{}{},
+ emptyListValue,
+ listType(emptyStructType),
+ },
+ {
+ "Null array of empty structs.",
+ []struct{}(nil),
+ nullProto(),
+ listType(emptyStructType),
+ },
+ } {
+ encodeStructValue(test, t)
+ }
+}
+
+func TestEncodeStructValueMixedStructTypes(t *testing.T) {
+ type staticStruct struct {
+ F int `spanner:"fStatic"`
+ }
+ s1 := staticStruct{10}
+ s2 := (*staticStruct)(nil)
+
+ var f float64
+ dynStructType := reflect.StructOf([]reflect.StructField{
+ {Name: "A", Type: reflect.TypeOf(f), Tag: `spanner:"fDynamic"`},
+ })
+ s3 := reflect.New(dynStructType)
+ s3.Elem().Field(0).SetFloat(3.14)
+
+ for _, test := range []encodeTest{
+ {
+ "'struct' with static and dynamic *struct, []*struct, []struct fields",
+ struct {
+ A []staticStruct
+ B []*staticStruct
+ C interface{}
+ }{
+ []staticStruct{s1, s1},
+ []*staticStruct{&s1, s2},
+ s3.Interface(),
+ },
+ listProto(
+ listProto(listProto(intProto(10)), listProto(intProto(10))),
+ listProto(listProto(intProto(10)), nullProto()),
+ listProto(floatProto(3.14))),
+ structType(
+ mkField("A", listType(structType(mkField("fStatic", intType())))),
+ mkField("B", listType(structType(mkField("fStatic", intType())))),
+ mkField("C", structType(mkField("fDynamic", floatType())))),
+ },
+ } {
+ encodeStructValue(test, t)
+ }
+}
+
+func TestBindParamsDynamic(t *testing.T) {
+ // Verify Statement.bindParams generates correct values and types.
+ st := Statement{
+ SQL: "SELECT id from t_foo WHERE col = @var",
+ Params: map[string]interface{}{"var": nil},
+ }
+ want := &sppb.ExecuteSqlRequest{
+ Params: &proto3.Struct{
+ Fields: map[string]*proto3.Value{"var": nil},
+ },
+ ParamTypes: map[string]*sppb.Type{"var": nil},
+ }
+ var (
+ t1, _ = time.Parse(time.RFC3339Nano, "2016-11-15T15:04:05.999999999Z")
+ // Boundaries
+ t2, _ = time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00.000000000Z")
+ )
+ dynamicStructType := reflect.StructOf([]reflect.StructField{
+ {Name: "A", Type: reflect.TypeOf(t1), Tag: `spanner:"field"`},
+ {Name: "B", Type: reflect.TypeOf(3.14), Tag: `spanner:""`},
+ })
+ dynamicStructArrType := reflect.SliceOf(reflect.PtrTo(dynamicStructType))
+ dynamicEmptyStructType := reflect.StructOf(make([]reflect.StructField, 0, 0))
+
+ dynamicStructTypeProto := structType(
+ mkField("field", timeType()),
+ mkField("", floatType()))
+
+ s3 := reflect.New(dynamicStructType)
+ s3.Elem().Field(0).Set(reflect.ValueOf(t1))
+ s3.Elem().Field(1).SetFloat(1.4)
+
+ s4 := reflect.New(dynamicStructType)
+ s4.Elem().Field(0).Set(reflect.ValueOf(t2))
+ s4.Elem().Field(1).SetFloat(-13.3)
+
+ dynamicStructArrayVal := reflect.MakeSlice(dynamicStructArrType, 2, 2)
+ dynamicStructArrayVal.Index(0).Set(s3)
+ dynamicStructArrayVal.Index(1).Set(s4)
+
+ for i, test := range []struct {
+ val interface{}
+ wantField *proto3.Value
+ wantType *sppb.Type
+ }{
+ {
+ s3.Interface(),
+ listProto(timeProto(t1), floatProto(1.4)),
+ structType(
+ mkField("field", timeType()),
+ mkField("", floatType())),
+ },
+ {
+ reflect.Zero(reflect.PtrTo(dynamicEmptyStructType)).Interface(),
+ nullProto(),
+ structType([]*sppb.StructType_Field{}...),
+ },
+ {
+ dynamicStructArrayVal.Interface(),
+ listProto(
+ listProto(timeProto(t1), floatProto(1.4)),
+ listProto(timeProto(t2), floatProto(-13.3))),
+ listType(dynamicStructTypeProto),
+ },
+ {
+ []*struct {
+ F1 time.Time `spanner:"field"`
+ F2 float64 `spanner:""`
+ }{
+ nil,
+ {t1, 1.4},
+ },
+ listProto(
+ nullProto(),
+ listProto(timeProto(t1), floatProto(1.4))),
+ listType(dynamicStructTypeProto),
+ },
+ } {
+ st.Params["var"] = test.val
+ want.Params.Fields["var"] = test.wantField
+ want.ParamTypes["var"] = test.wantType
+ got := &sppb.ExecuteSqlRequest{}
+ if err := st.bindParams(got); err != nil || !proto.Equal(got, want) {
+ // handle NaN
+ if test.wantType.Code == floatType().Code && proto.MarshalTextString(got) == proto.MarshalTextString(want) {
+ continue
+ }
+ t.Errorf("#%d: bind result: \n(%v, %v)\nwant\n(%v, %v)\n", i, got, err, want, nil)
+ }
+ }
+}
+
+func TestStructParametersBind(t *testing.T) {
+ t.Parallel()
+ ctx := context.Background()
+ client, _, cleanup := prepare(ctx, t, nil)
+ defer cleanup()
+
+ type tRow []interface{}
+ type tRows []struct{ trow tRow }
+
+ type allFields struct {
+ Stringf string
+ Intf int
+ Boolf bool
+ Floatf float64
+ Bytef []byte
+ Timef time.Time
+ Datef civil.Date
+ }
+ allColumns := []string{
+ "Stringf",
+ "Intf",
+ "Boolf",
+ "Floatf",
+ "Bytef",
+ "Timef",
+ "Datef",
+ }
+ s1 := allFields{"abc", 300, false, 3.45, []byte("foo"), t1, d1}
+ s2 := allFields{"def", -300, false, -3.45, []byte("bar"), t2, d2}
+
+ dynamicStructType := reflect.StructOf([]reflect.StructField{
+ {Name: "A", Type: reflect.TypeOf(t1), Tag: `spanner:"ff1"`},
+ })
+ s3 := reflect.New(dynamicStructType)
+ s3.Elem().Field(0).Set(reflect.ValueOf(t1))
+
+ for i, test := range []struct {
+ param interface{}
+ sql string
+ cols []string
+ trows tRows
+ }{
+ // Struct value.
+ {
+ s1,
+ "SELECT" +
+ " @p.Stringf," +
+ " @p.Intf," +
+ " @p.Boolf," +
+ " @p.Floatf," +
+ " @p.Bytef," +
+ " @p.Timef," +
+ " @p.Datef",
+ allColumns,
+ tRows{
+ {tRow{"abc", 300, false, 3.45, []byte("foo"), t1, d1}},
+ },
+ },
+ // Array of struct value.
+ {
+ []allFields{s1, s2},
+ "SELECT * FROM UNNEST(@p)",
+ allColumns,
+ tRows{
+ {tRow{"abc", 300, false, 3.45, []byte("foo"), t1, d1}},
+ {tRow{"def", -300, false, -3.45, []byte("bar"), t2, d2}},
+ },
+ },
+ // Null struct.
+ {
+ (*allFields)(nil),
+ "SELECT @p IS NULL",
+ []string{""},
+ tRows{
+ {tRow{true}},
+ },
+ },
+ // Null Array of struct.
+ {
+ []allFields(nil),
+ "SELECT @p IS NULL",
+ []string{""},
+ tRows{
+ {tRow{true}},
+ },
+ },
+ // Empty struct.
+ {
+ struct{}{},
+ "SELECT @p IS NULL ",
+ []string{""},
+ tRows{
+ {tRow{false}},
+ },
+ },
+ // Empty array of struct.
+ {
+ []allFields{},
+ "SELECT * FROM UNNEST(@p) ",
+ allColumns,
+ tRows{},
+ },
+ // Struct with duplicate fields.
+ {
+ struct {
+ A int `spanner:"field"`
+ B int `spanner:"field"`
+ }{10, 20},
+ "SELECT * FROM UNNEST([@p]) ",
+ []string{"field", "field"},
+ tRows{
+ {tRow{10, 20}},
+ },
+ },
+ // Struct with unnamed fields.
+ {
+ struct {
+ A string `spanner:""`
+ }{"hello"},
+ "SELECT * FROM UNNEST([@p]) ",
+ []string{""},
+ tRows{
+ {tRow{"hello"}},
+ },
+ },
+ // Mixed struct.
+ {
+ struct {
+ DynamicStructField interface{} `spanner:"f1"`
+ ArrayStructField []*allFields `spanner:"f2"`
+ }{
+ DynamicStructField: s3.Interface(),
+ ArrayStructField: []*allFields{nil},
+ },
+ "SELECT @p.f1.ff1, ARRAY_LENGTH(@p.f2), @p.f2[OFFSET(0)] IS NULL ",
+ []string{"ff1", "", ""},
+ tRows{
+ {tRow{t1, 1, true}},
+ },
+ },
+ } {
+ iter := client.Single().Query(ctx, Statement{
+ SQL: test.sql,
+ Params: map[string]interface{}{"p": test.param},
+ })
+ var gotRows []*Row
+ err := iter.Do(func(r *Row) error {
+ gotRows = append(gotRows, r)
+ return nil
+ })
+ if err != nil {
+ t.Errorf("Failed to execute test case %d, error: %v", i, err)
+ }
+
+ var wantRows []*Row
+ for j, row := range test.trows {
+ r, err := NewRow(test.cols, row.trow)
+ if err != nil {
+ t.Errorf("Invalid row %d in test case %d", j, i)
+ }
+ wantRows = append(wantRows, r)
+ }
+ if !testEqual(gotRows, wantRows) {
+ t.Errorf("%d: Want result %v, got result %v", i, wantRows, gotRows)
+ }
+ }
+}
diff --git a/storage/go17.go b/storage/go17.go
deleted file mode 100644
index 11b5982..0000000
--- a/storage/go17.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2017 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build go1.7
-
-package storage
-
-import (
- "context"
- "net/http"
-)
-
-func withContext(ctx context.Context, r *http.Request) *http.Request {
- return r.WithContext(ctx)
-}
-
-func goHTTPUncompressed(res *http.Response) bool {
- return res.Uncompressed
-}
diff --git a/storage/not_go17.go b/storage/not_go17.go
deleted file mode 100644
index 744985f..0000000
--- a/storage/not_go17.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2017 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !go1.7
-
-package storage
-
-import (
- "net/http"
-)
-
-func withContext(_ interface{}, r *http.Request) *http.Request {
- // In Go 1.6 and below, ignore the context.
- return r
-}
-
-// Go 1.6 doesn't have http.Response.Uncompressed, so we can't know whether the Go
-// HTTP stack uncompressed a gzip file. As a good approximation, assume that
-// the lack of a Content-Length header means that it did uncompress.
-func goHTTPUncompressed(res *http.Response) bool {
- return res.Header.Get("Content-Length") == ""
-}
diff --git a/storage/oc_test.go b/storage/oc_test.go
index 7bb9d12..2143396 100644
--- a/storage/oc_test.go
+++ b/storage/oc_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.8
-
package storage
import (
diff --git a/storage/reader.go b/storage/reader.go
index 33c5d87..50f381f 100644
--- a/storage/reader.go
+++ b/storage/reader.go
@@ -107,7 +107,7 @@
if err != nil {
return nil, err
}
- req = withContext(ctx, req)
+ req = req.WithContext(ctx)
if o.userProject != "" {
req.Header.Set("X-Goog-User-Project", o.userProject)
}
@@ -202,7 +202,7 @@
// The problem with the last two cases is that the CRC will not match -- GCS
// computes it on the compressed contents, but we compute it on the
// uncompressed contents.
- if length != 0 && !goHTTPUncompressed(res) && !uncompressedByServer(res) {
+ if length != 0 && !res.Uncompressed && !uncompressedByServer(res) {
crc, checkCRC = parseCRC32c(res)
}
}
diff --git a/trace/http.go b/trace/http.go
index 7eae322..6a64465 100644
--- a/trace/http.go
+++ b/trace/http.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.7
-
package trace
import (
diff --git a/trace/http_test.go b/trace/http_test.go
index bf8ebd3..93cc1b0 100644
--- a/trace/http_test.go
+++ b/trace/http_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.7
-
package trace
import (
diff --git a/trace/httpexample_test.go b/trace/httpexample_test.go
index 4eaee09..2af4ead 100644
--- a/trace/httpexample_test.go
+++ b/trace/httpexample_test.go
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build go1.7
-
package trace_test
import (