@@ -175,15 +175,15 @@ func (s ClickHouseSuite) GetRows(table string, cols string) (*model.QRecordBatch
175175
176176 batch := & model.QRecordBatch {}
177177 colTypes := rows .ColumnTypes ()
178- row := make ([]any , 0 , len (colTypes ))
178+ scanTypes := make ([]reflect. Type , len (colTypes ))
179179 tableSchema , err := connclickhouse .GetTableSchemaForTable (& protos.TableMapping {SourceTableIdentifier : table }, colTypes )
180180 if err != nil {
181181 return nil , err
182182 }
183183
184184 for idx , ty := range colTypes {
185185 fieldDesc := tableSchema .Columns [idx ]
186- row = append ( row , reflect . New ( ty .ScanType ()). Interface () )
186+ scanTypes [ idx ] = ty .ScanType ()
187187 batch .Schema .Fields = append (batch .Schema .Fields , types.QField {
188188 Name : ty .Name (),
189189 Type : types .QValueKind (fieldDesc .Type ),
@@ -194,6 +194,13 @@ func (s ClickHouseSuite) GetRows(table string, cols string) (*model.QRecordBatch
194194 }
195195
196196 for rows .Next () {
197+ // Allocate fresh scan targets per row: clickhouse-go does not reset a
198+ // nullable destination to nil when scanning a NULL, so a reused buffer
199+ // would make a NULL row inherit the previous row's value.
200+ row := make ([]any , len (scanTypes ))
201+ for idx , st := range scanTypes {
202+ row [idx ] = reflect .New (st ).Interface ()
203+ }
197204 if err := rows .Scan (row ... ); err != nil {
198205 return nil , err
199206 }
0 commit comments