@@ -773,7 +773,7 @@ func (r *Rows) StructScan(dest interface{}) error {
773773 r .started = true
774774 }
775775
776- err := fieldsByTraversal (v , r .fields , r .values , true )
776+ err := fieldsByTraversal (v , r .fields , r .values )
777777 if err != nil {
778778 return err
779779 }
@@ -990,7 +990,7 @@ func (r *Row) scanAny(dest interface{}, structOnly bool) error {
990990 }
991991 values := make ([]interface {}, len (columns ))
992992
993- err = fieldsByTraversal (v , fields , values , true )
993+ err = fieldsByTraversal (v , fields , values )
994994 if err != nil {
995995 return err
996996 }
@@ -1165,7 +1165,7 @@ func scanAll(rows rowsi, dest interface{}, structOnly bool) error {
11651165 vp = reflect .New (base )
11661166 v = reflect .Indirect (vp )
11671167
1168- err = fieldsByTraversal (v , fields , values , true )
1168+ err = fieldsByTraversal (v , fields , values )
11691169 if err != nil {
11701170 return err
11711171 }
@@ -1231,7 +1231,7 @@ func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) {
12311231// when iterating over many rows. Empty traversals will get an interface pointer.
12321232// Because of the necessity of requesting ptrs or values, it's considered a bit too
12331233// specialized for inclusion in reflectx itself.
1234- func fieldsByTraversal (v reflect.Value , traversals [][]int , values []interface {}, ptrs bool ) error {
1234+ func fieldsByTraversal (v reflect.Value , traversals [][]int , values []interface {}) error {
12351235 v = reflect .Indirect (v )
12361236 if v .Kind () != reflect .Struct {
12371237 return errors .New ("argument not a struct" )
@@ -1240,23 +1240,37 @@ func fieldsByTraversal(v reflect.Value, traversals [][]int, values []interface{}
12401240 for i , traversal := range traversals {
12411241 if len (traversal ) == 0 {
12421242 values [i ] = new (interface {})
1243- continue
1244- }
1245- f := reflectx .FieldByIndexes (v , traversal )
1246- if ptrs {
1247- values [i ] = f .Addr ().Interface ()
1243+ } else if len (traversal ) == 1 {
1244+ values [i ] = reflectx .FieldByIndexes (v , traversal ).Addr ().Interface ()
12481245 } else {
1249- values [i ] = f .Interface ()
1246+ // reflectx.FieldByIndexes initializes pointer fields, including pointers to nested structs.
1247+ // Use optDest to delay it until the first non-NULL value is scanned into a field of a nested struct.
1248+ // That way we can support LEFT JOINs with optional nested structs.
1249+ values [i ] = optDest (func () interface {} {
1250+ return reflectx .FieldByIndexes (v , traversal ).Addr ().Interface ()
1251+ })
12501252 }
12511253 }
12521254 return nil
12531255}
12541256
1255- func missingFields (transversals [][]int ) (field int , err error ) {
1256- for i , t := range transversals {
1257+ func missingFields (traversals [][]int ) (field int , err error ) {
1258+ for i , t := range traversals {
12571259 if len (t ) == 0 {
12581260 return i , errors .New ("missing field" )
12591261 }
12601262 }
12611263 return 0 , nil
12621264}
1265+
1266+ // optDest will only forward the Scan to the nested value if
1267+ // the database value is not nil.
1268+ type optDest func () interface {}
1269+
1270+ // Scan implements sql.Scanner.
1271+ func (dest optDest ) Scan (src interface {}) error {
1272+ if src == nil {
1273+ return nil
1274+ }
1275+ return convertAssign (dest (), src )
1276+ }
0 commit comments