From 0f6f235cdff24841e0616df3b774fdaf3cfe5f35 Mon Sep 17 00:00:00 2001 From: Scott Lepper Date: Mon, 29 Apr 2024 15:04:26 +0100 Subject: [PATCH] fix: dynamic frame panic (#958) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: dynamic frame panic --------- Co-authored-by: Andres Martinez Gotor Co-authored-by: Zoltán Bedi --- data/sqlutil/dynamic_frame.go | 11 +++++--- data/sqlutil/dynamic_frame_test.go | 40 ++++++++++++++++++++++++++++++ data/sqlutil/sql.go | 4 ++- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/data/sqlutil/dynamic_frame.go b/data/sqlutil/dynamic_frame.go index 5d9507437..fc7a5066b 100644 --- a/data/sqlutil/dynamic_frame.go +++ b/data/sqlutil/dynamic_frame.go @@ -10,13 +10,18 @@ import ( const STRING = "string" -func isDynamic(converters []Converter) bool { +// removeDynamicConverter filters out the dynamic converter. It is not a valid converter. +func removeDynamicConverter(converters []Converter) (bool, []Converter) { + var filtered []Converter + var isDynamic bool for _, conv := range converters { if conv.Dynamic { - return true + isDynamic = true + } else { + filtered = append(filtered, conv) } } - return false + return isDynamic, filtered } func findDataTypes(rows Rows, rowLimit int64, types []*sql.ColumnType) ([]Field, [][]interface{}, error) { diff --git a/data/sqlutil/dynamic_frame_test.go b/data/sqlutil/dynamic_frame_test.go index 62ca51108..f09a4d632 100644 --- a/data/sqlutil/dynamic_frame_test.go +++ b/data/sqlutil/dynamic_frame_test.go @@ -29,6 +29,7 @@ func TestDynamicFrame(t *testing.T) { itr: mock, } + _, converters = removeDynamicConverter(converters) frame, err := frameDynamic(rows, 100, types, converters) assert.Nil(t, err) assert.NotNil(t, frame) @@ -64,3 +65,42 @@ func (rs *MockRows) Scan(dest ...interface{}) error { } return nil } + +func TestDynamicFrameShouldNotPanic(t *testing.T) { + kind := &sql.ColumnType{} + types := []*sql.ColumnType{} + types = append(types, kind) + converters := []Converter{dynamic()} + data := [][]interface{}{} + mockRow := []interface{}{} + val := string("foo") + mockRow = append(mockRow, val) + data = append(data, mockRow) + mock := &MockRows{ + data: data, + index: -1, + } + rows := Rows{ + itr: mock, + } + + _, converters = removeDynamicConverter(converters) + frame, err := frameDynamic(rows, 100, types, converters) + assert.Nil(t, err) + assert.NotNil(t, frame) + + assert.Equal(t, 1, frame.Rows()) + + actual := frame.Fields[0].At(0).(*string) + assert.Equal(t, val, *actual) +} + +// dynamic is the converter that uses the results to determine data types +func dynamic() Converter { + kind := "dynamic" + return Converter{ + Name: kind, + InputTypeName: kind, + Dynamic: true, + } +} diff --git a/data/sqlutil/sql.go b/data/sqlutil/sql.go index 3aab12425..e0eb0b4e6 100644 --- a/data/sqlutil/sql.go +++ b/data/sqlutil/sql.go @@ -25,7 +25,9 @@ func FrameFromRows(rows *sql.Rows, rowLimit int64, converters ...Converter) (*da return nil, err } - if isDynamic(converters) { + // If there is a dynamic converter, we need to use the dynamic framer + // and remove the dynamic converter from the list of converters ( it is not valid, just a flag ) + if isDynamic, converters := removeDynamicConverter(converters); isDynamic { rows := Rows{itr: rows} return frameDynamic(rows, rowLimit, types, converters) }