diff --git a/pkg/sqlcmd/sqlcmd.go b/pkg/sqlcmd/sqlcmd.go index 93637a02..09adb9e7 100644 --- a/pkg/sqlcmd/sqlcmd.go +++ b/pkg/sqlcmd/sqlcmd.go @@ -446,6 +446,18 @@ func (s *Sqlcmd) getRunnableQuery(q string) string { return b.String() } +// safeColumnTypes wraps rows.ColumnTypes() with panic recovery. +// The go-mssqldb driver panics for unsupported types like GEOGRAPHY/GEOMETRY (type 240). +func safeColumnTypes(rows *sql.Rows) (cols []*sql.ColumnType, err error) { + defer func() { + if r := recover(); r != nil { + err = localizer.Errorf("unsupported column type: %v", r) + cols = nil + } + }() + return rows.ColumnTypes() +} + // runQuery runs the query and prints the results // The return value is based on the first cell of the last column of the last result set. // If it's numeric, it will be converted to int @@ -509,7 +521,7 @@ func (s *Sqlcmd) runQuery(query string) (int, error) { case sqlexp.MsgNext: if first { first = false - cols, err = rows.ColumnTypes() + cols, err = safeColumnTypes(rows) if err != nil { retcode = -100 qe = s.handleError(&retcode, err) diff --git a/pkg/sqlcmd/sqlcmd_test.go b/pkg/sqlcmd/sqlcmd_test.go index ade6dd8c..1a7116c9 100644 --- a/pkg/sqlcmd/sqlcmd_test.go +++ b/pkg/sqlcmd/sqlcmd_test.go @@ -721,3 +721,12 @@ func TestSqlcmdPrefersSharedMemoryProtocol(t *testing.T) { assert.EqualValuesf(t, "np", msdsn.ProtocolParsers[3].Protocol(), "np should be fourth protocol") } + +func TestSafeColumnTypesRecoversPanic(t *testing.T) { + // A nil *sql.Rows will panic when ColumnTypes() is called. + // safeColumnTypes should recover and return an error instead. + var rows *sql.Rows + cols, err := safeColumnTypes(rows) + assert.Nil(t, cols) + assert.Error(t, err) +}