diff --git a/bigquery/params.go b/bigquery/params.go index 5cafbf85f06..bdbe9a94710 100644 --- a/bigquery/params.go +++ b/bigquery/params.go @@ -21,6 +21,7 @@ import ( "math/big" "reflect" "regexp" + "strings" "time" "cloud.google.com/go/civil" @@ -380,6 +381,12 @@ func paramType(t reflect.Type, v reflect.Value) (*bq.QueryParameterType, error) return nil, err } for _, f := range fields { + prefixes := []string{"*", "[]"} // check pointer and arrays + for _, prefix := range prefixes { + if strings.TrimPrefix(t.String(), prefix) == strings.TrimPrefix(f.Type.String(), prefix) { + return nil, fmt.Errorf("bigquery: Go type %s cannot be represented as a parameter due to an attribute cycle/recursion detected", t) + } + } pt, err := paramType(f.Type, v) if err != nil { return nil, err diff --git a/bigquery/params_test.go b/bigquery/params_test.go index fa6a293051d..ceb8af0dd64 100644 --- a/bigquery/params_test.go +++ b/bigquery/params_test.go @@ -282,10 +282,46 @@ func TestParamType(t *testing.T) { } } } - func TestParamTypeErrors(t *testing.T) { for _, val := range []interface{}{ - nil, uint(0), new([]int), make(chan int), + nil, uint(0), new([]int), make(chan int), map[string]interface{}{}, + } { + _, err := paramType(reflect.TypeOf(val), reflect.ValueOf(val)) + if err == nil { + t.Errorf("%v (%T): got nil, want error", val, val) + } + } + + type recArr struct { + RecArr []recArr + } + type recMap struct { + RecMap map[string]recMap + } + queryParam := QueryParameterValue{ + StructValue: map[string]QueryParameterValue{ + "nested": { + Type: StandardSQLDataType{ + TypeKind: "STRING", + }, + Value: "TEST", + }, + }, + } + standardSQL := StandardSQLDataType{ + ArrayElementType: &StandardSQLDataType{ + TypeKind: "NUMERIC", + }, + } + recursiveArr := recArr{ + RecArr: []recArr{}, + } + recursiveMap := recMap{ + RecMap: map[string]recMap{}, + } + // Recursive structs + for _, val := range []interface{}{ + queryParam, standardSQL, recursiveArr, recursiveMap, } { _, err := paramType(reflect.TypeOf(val), reflect.ValueOf(val)) if err == nil {