Skip to content

Commit a356b9a

Browse files
authored
Fixed type hashing for Full-Text (#1963)
Cover additional types (Time, GeometryValue, JSONDocument) missing in first pass of full text indexes.
1 parent 6fe6d0c commit a356b9a

File tree

2 files changed

+97
-43
lines changed

2 files changed

+97
-43
lines changed

enginetest/enginetests.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3529,6 +3529,28 @@ func TestFulltextIndexes(t *testing.T, harness Harness) {
35293529
for _, script := range queries.FulltextTests {
35303530
TestScript(t, harness, script)
35313531
}
3532+
t.Run("Type Hashing", func(t *testing.T) {
3533+
for _, script := range queries.TypeWireTests {
3534+
t.Run(script.Name, func(t *testing.T) {
3535+
e := mustNewEngine(t, harness)
3536+
defer e.Close()
3537+
3538+
for _, statement := range script.SetUpScript {
3539+
if sh, ok := harness.(SkippingHarness); ok {
3540+
if sh.SkipQueryTest(statement) {
3541+
t.Skip()
3542+
}
3543+
}
3544+
ctx := NewContext(harness).WithQuery(statement)
3545+
RunQueryWithContext(t, e, harness, ctx, statement)
3546+
}
3547+
3548+
ctx := NewContext(harness)
3549+
RunQueryWithContext(t, e, harness, ctx, "ALTER TABLE test ADD COLUMN extracol VARCHAR(200) DEFAULT '';")
3550+
RunQueryWithContext(t, e, harness, ctx, "CREATE FULLTEXT INDEX idx ON test (extracol);")
3551+
})
3552+
}
3553+
})
35323554
}
35333555

35343556
// todo(max): rewrite this using info schema and []QueryTest

sql/fulltext/fulltext.go

Lines changed: 75 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)