@@ -19,8 +19,10 @@ import (
1919 "encoding/binary"
2020 "encoding/hex"
2121 "fmt"
22+ "hash"
2223 "io"
2324 "strings"
25+ "time"
2426
2527 "github.com/shopspring/decimal"
2628
@@ -99,49 +101,10 @@ func HashRow(row sql.Row) (string, error) {
99101 // give us a unique representation for representing NULL values.
100102 valIsNull := make ([]bool , len (row ))
101103 for i , val := range row {
102- switch val := val .(type ) {
103- case int :
104- if err := binary .Write (h , binary .LittleEndian , int64 (val )); err != nil {
105- return "" , err
106- }
107- case uint :
108- if err := binary .Write (h , binary .LittleEndian , uint64 (val )); err != nil {
109- return "" , err
110- }
111- case string :
112- if _ , err := h .Write ([]byte (val )); err != nil {
113- return "" , err
114- }
115- case []byte :
116- if _ , err := h .Write (val ); err != nil {
117- return "" , err
118- }
119- case decimal.Decimal :
120- bytes , err := val .GobEncode ()
121- if err != nil {
122- return "" , err
123- }
124- if _ , err := h .Write (bytes ); err != nil {
125- return "" , err
126- }
127- case decimal.NullDecimal :
128- if ! val .Valid {
129- valIsNull [i ] = true
130- } else {
131- bytes , err := val .Decimal .GobEncode ()
132- if err != nil {
133- return "" , err
134- }
135- if _ , err := h .Write (bytes ); err != nil {
136- return "" , err
137- }
138- }
139- case nil :
140- valIsNull [i ] = true
141- default :
142- if err := binary .Write (h , binary .LittleEndian , val ); err != nil {
143- return "" , err
144- }
104+ var err error
105+ valIsNull [i ], err = writeHashedValue (h , val )
106+ if err != nil {
107+ return "" , err
145108 }
146109 }
147110
@@ -153,6 +116,75 @@ func HashRow(row sql.Row) (string, error) {
153116 return strings .ToLower (hex .EncodeToString (h .Sum (nil ))), nil
154117}
155118
119+ // writeHashedValue writes the given value into the hash.
120+ func writeHashedValue (h hash.Hash , val interface {}) (valIsNull bool , err error ) {
121+ switch val := val .(type ) {
122+ case int :
123+ if err := binary .Write (h , binary .LittleEndian , int64 (val )); err != nil {
124+ return false , err
125+ }
126+ case uint :
127+ if err := binary .Write (h , binary .LittleEndian , uint64 (val )); err != nil {
128+ return false , err
129+ }
130+ case string :
131+ if _ , err := h .Write ([]byte (val )); err != nil {
132+ return false , err
133+ }
134+ case []byte :
135+ if _ , err := h .Write (val ); err != nil {
136+ return false , err
137+ }
138+ case decimal.Decimal :
139+ bytes , err := val .GobEncode ()
140+ if err != nil {
141+ return false , err
142+ }
143+ if _ , err := h .Write (bytes ); err != nil {
144+ return false , err
145+ }
146+ case decimal.NullDecimal :
147+ if ! val .Valid {
148+ return true , nil
149+ } else {
150+ bytes , err := val .Decimal .GobEncode ()
151+ if err != nil {
152+ return false , err
153+ }
154+ if _ , err := h .Write (bytes ); err != nil {
155+ return false , err
156+ }
157+ }
158+ case time.Time :
159+ bytes , err := val .MarshalBinary ()
160+ if err != nil {
161+ return false , err
162+ }
163+ if _ , err := h .Write (bytes ); err != nil {
164+ return false , err
165+ }
166+ case types.GeometryValue :
167+ if _ , err := h .Write (val .Serialize ()); err != nil {
168+ return false , err
169+ }
170+ case types.JSONDocument :
171+ str , err := val .ToString (sql .NewEmptyContext ())
172+ if err != nil {
173+ return false , err
174+ }
175+ if _ , err := h .Write ([]byte (str )); err != nil {
176+ return false , err
177+ }
178+ case nil :
179+ return true , nil
180+ default :
181+ if err := binary .Write (h , binary .LittleEndian , val ); err != nil {
182+ return false , err
183+ }
184+ }
185+ return false , nil
186+ }
187+
156188// GetKeyColumns returns the key columns from the parent table that will be used to uniquely reference any given row on
157189// the parent table. For many tables, this will be the primary key. For tables that do not have a valid key, the columns
158190// will be much more important.
0 commit comments