Skip to content

Commit 2ba02ea

Browse files
committed
bug fixes and more testing
1 parent ea4e3e9 commit 2ba02ea

5 files changed

Lines changed: 242 additions & 50 deletions

File tree

server/ast/resolvable_type_reference.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,11 @@ func nodeResolvableTypeReference(ctx *Context, typ tree.ResolvableTypeReference)
156156
} else if width == 0 {
157157
// TODO: need to differentiate between definitions 'varchar' (valid) and 'varchar(0)' (invalid)
158158
resolvedType = pgtypes.VarChar
159-
}
160-
resolvedType, err = pgtypes.NewVarCharType(int32(width))
161-
if err != nil {
162-
return nil, nil, err
159+
} else {
160+
resolvedType, err = pgtypes.NewVarCharType(int32(width))
161+
if err != nil {
162+
return nil, nil, err
163+
}
163164
}
164165
case oid.T_xid:
165166
resolvedType = pgtypes.Xid
@@ -170,11 +171,11 @@ func nodeResolvableTypeReference(ctx *Context, typ tree.ResolvableTypeReference)
170171
} else if width == 0 {
171172
// TODO: need to differentiate between definitions 'bit' (valid) and 'bit(0)' (invalid)
172173
resolvedType = pgtypes.Bit
173-
}
174-
175-
resolvedType, err = pgtypes.NewBitType(int32(width))
176-
if err != nil {
177-
return nil, nil, err
174+
} else {
175+
resolvedType, err = pgtypes.NewBitType(int32(width))
176+
if err != nil {
177+
return nil, nil, err
178+
}
178179
}
179180
case oid.T_varbit:
180181
width := uint32(columnType.Width())
@@ -183,11 +184,11 @@ func nodeResolvableTypeReference(ctx *Context, typ tree.ResolvableTypeReference)
183184
} else if width == 0 {
184185
// TODO: need to differentiate between definitions 'varbit' (valid) and 'varbit(0)' (invalid)
185186
resolvedType = pgtypes.VarBit
186-
}
187-
188-
resolvedType, err = pgtypes.NewVarBitType(int32(width))
189-
if err != nil {
190-
return nil, nil, err
187+
} else {
188+
resolvedType, err = pgtypes.NewVarBitType(int32(width))
189+
if err != nil {
190+
return nil, nil, err
191+
}
191192
}
192193
default:
193194
return nil, nil, errors.Errorf("unknown type with oid: %d", uint32(columnType.Oid()))

server/functions/framework/cast.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ func GetImplicitCast(fromType *pgtypes.DoltgresType, toType *pgtypes.DoltgresTyp
223223

224224
// addTypeCast registers the given type cast.
225225
func addTypeCast(mutex *sync.RWMutex,
226-
castMap map[id.Type]map[id.Type]pgtypes.TypeCastFunction,
227-
castArray map[id.Type][]*pgtypes.DoltgresType, cast TypeCast) error {
226+
castMap map[id.Type]map[id.Type]pgtypes.TypeCastFunction,
227+
castArray map[id.Type][]*pgtypes.DoltgresType, cast TypeCast) error {
228228
mutex.Lock()
229229
defer mutex.Unlock()
230230

@@ -254,8 +254,8 @@ func getPotentialCasts(mutex *sync.RWMutex, castArray map[id.Type][]*pgtypes.Dol
254254
// getCast returns the type cast function that will cast the "from" type to the "to" type. Returns nil if such a cast is
255255
// not valid.
256256
func getCast(mutex *sync.RWMutex,
257-
castMap map[id.Type]map[id.Type]pgtypes.TypeCastFunction,
258-
fromType *pgtypes.DoltgresType, toType *pgtypes.DoltgresType, outerFunc getCastFunction) pgtypes.TypeCastFunction {
257+
castMap map[id.Type]map[id.Type]pgtypes.TypeCastFunction,
258+
fromType *pgtypes.DoltgresType, toType *pgtypes.DoltgresType, outerFunc getCastFunction) pgtypes.TypeCastFunction {
259259
mutex.RLock()
260260
defer mutex.RUnlock()
261261

server/functions/varchar.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,13 @@ var varcharout = framework.Function1{
6464
Parameters: [1]*pgtypes.DoltgresType{pgtypes.VarChar},
6565
Strict: true,
6666
Callable: func(ctx *sql.Context, t [2]*pgtypes.DoltgresType, val any) (any, error) {
67-
v := val.(string)
67+
v, ok, err := sql.Unwrap[string](ctx, val)
68+
if err != nil {
69+
return nil, err
70+
}
71+
if !ok {
72+
return nil, fmt.Errorf(`"varcharout" requires a string argument, got %T`, val)
73+
}
6874
typ := t[0]
6975
tm := typ.GetAttTypMod()
7076
if tm != -1 {

testing/go/adaptive_encoding_test.go

Lines changed: 186 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -48,38 +48,193 @@ var halfSizeString = string(makeTestBytes(2000, 2))
4848
// We expect a tuple to never store this value out-of-band.
4949
var tinyString = string(makeTestBytes(10, 3))
5050

51-
func TestAdaptiveEncoding(t *testing.T) {
52-
columnType := "text"
51+
// A 4000 byte file starting with ascii byte 1 and then consisting of all zeros.
52+
// This is larger than default target tuple size for outlining adaptive types.
53+
// We expect a tuple to always store this value out-of-band
54+
var fullSizeVarbit = string(makeTestBytes(4000, '1'))
55+
56+
// A 2000 byte file starting with ascii byte 1 and then consisting of all zeros.
57+
// This is over half of the default target tuple size for outlining adaptive types.
58+
// We expect a tuple to be able to store this value inline once, but not twice.
59+
var halfSizeVarbit = string(makeTestBytes(2000, '1'))
60+
61+
// A 10 byte file starting with ascii byte 1 and then consisting of 10 zero bytes.
62+
// This is file is smaller than an address hash.
63+
// We expect a tuple to never store this value out-of-band.
64+
var tinyVarbit = string(makeTestBytes(10, '1'))
65+
66+
func TestAdaptiveEncodingText(t *testing.T) {
5367
fullSizeOutOfLineRepr := fullSizeString
68+
columnTypes := []string{"varchar", "text"}
69+
for _, columnType := range columnTypes {
70+
t.Run(columnType, func(t *testing.T) {
71+
RunScripts(t, []ScriptTest{
72+
{
73+
Name: "Adaptive Encoding With One Column",
74+
SetUpScript: setup.SetupScript{
75+
fmt.Sprintf(`create table blobt (i char(1) primary key, b %s);`, columnType),
76+
fmt.Sprintf(`create table blobt2 (i char(2) primary key, b1 %s, b2 %s);`, columnType, columnType),
77+
`insert into blobt values
78+
('F', LOAD_FILE('testdata/fullSize')),
79+
('H', LOAD_FILE('testdata/halfSize')),
80+
('T', LOAD_FILE('testdata/tinyFile'))`,
81+
},
82+
Assertions: []ScriptTestAssertion{
83+
{
84+
Query: "select b from blobt where i = 'F'",
85+
Expected: []sql.Row{{fullSizeString}},
86+
},
87+
{
88+
// Files that can fit within a tuple are stored inline.
89+
Query: "select b from blobt where i = 'H'",
90+
Expected: []sql.Row{{halfSizeString}},
91+
},
92+
{
93+
// An inlined adaptive column can be used in a filter.
94+
Query: "select i from blobt where b = LOAD_FILE('testdata/fullSize')",
95+
Expected: []sql.Row{{"F"}},
96+
},
97+
{
98+
// An out-of-line adaptive column can be used in a filter.
99+
Query: "select i from blobt where b = LOAD_FILE('testdata/halfSize')",
100+
Expected: []sql.Row{{"H"}},
101+
},
102+
},
103+
},
104+
{
105+
Name: "Adaptive Encoding With Two Columns",
106+
SetUpScript: setup.SetupScript{
107+
fmt.Sprintf(`create table blobt2 (i char(2) primary key, b1 %s, b2 %s);`, columnType, columnType),
108+
`insert into blobt2 values
109+
('FF', LOAD_FILE('testdata/fullSize'), LOAD_FILE('testdata/fullSize')),
110+
('HF', LOAD_FILE('testdata/halfSize'), LOAD_FILE('testdata/fullSize')),
111+
('TF', LOAD_FILE('testdata/tinyFile'), LOAD_FILE('testdata/fullSize')),
112+
('FH', LOAD_FILE('testdata/fullSize'), LOAD_FILE('testdata/halfSize')),
113+
('HH', LOAD_FILE('testdata/halfSize'), LOAD_FILE('testdata/halfSize')),
114+
('TH', LOAD_FILE('testdata/tinyFile'), LOAD_FILE('testdata/halfSize')),
115+
('FT', LOAD_FILE('testdata/fullSize'), LOAD_FILE('testdata/tinyFile')),
116+
('HT', LOAD_FILE('testdata/halfSize'), LOAD_FILE('testdata/tinyFile')),
117+
('TT', LOAD_FILE('testdata/tinyFile'), LOAD_FILE('testdata/tinyFile'))`,
118+
},
119+
Assertions: []ScriptTestAssertion{
120+
{
121+
// When a tuple with multiple adaptive columns is too large, columns are moved out-of-band from left to right.
122+
// However, strings smaller than the address size (20 bytes) are never stored out-of-band.
123+
Query: "select i, b1, b2 from blobt2",
124+
Expected: []sql.Row{
125+
{"FF", fullSizeString, fullSizeString},
126+
{"HF", halfSizeString, fullSizeString},
127+
{"TF", tinyString, fullSizeString},
128+
{"FH", fullSizeString, halfSizeString},
129+
{"HH", halfSizeString, halfSizeString},
130+
{"TH", tinyString, halfSizeString},
131+
{"FT", fullSizeString, tinyString},
132+
{"HT", halfSizeString, tinyString},
133+
{"TT", tinyString, tinyString},
134+
},
135+
},
136+
{
137+
// An adaptive column can be used in a filter when it doesn't have the same encoding in all rows.
138+
Query: "select i from blobt2 where b1 = LOAD_FILE('testdata/halfSize')",
139+
Expected: []sql.Row{{"HF"}, {"HH"}, {"HT"}},
140+
},
141+
{
142+
// An adaptive column can be used in a filter when it doesn't have the same encoding in all rows.
143+
Query: "select i from blobt2 where b2 = LOAD_FILE('testdata/halfSize')",
144+
Expected: []sql.Row{{"FH"}, {"HH"}, {"TH"}},
145+
},
146+
{
147+
// Test creating an index on an adaptive encoding column, matching against out-of-band values
148+
Query: "CREATE INDEX bidx ON blobt2 (b1)",
149+
},
150+
{
151+
Query: "select i, b1 FROM blobt2 WHERE b1 LIKE '\x01%'",
152+
Expected: []sql.Row{
153+
{"FF", fullSizeOutOfLineRepr},
154+
{"FH", fullSizeOutOfLineRepr},
155+
{"FT", fullSizeOutOfLineRepr},
156+
},
157+
},
158+
{
159+
// Test creating an index on an adaptive encoding column, matching against inline values
160+
Query: "CREATE INDEX bidx2 ON blobt2 (b2)",
161+
},
162+
{
163+
Query: "select i, b2 FROM blobt2 WHERE b2 LIKE '\x02%'",
164+
Expected: []sql.Row{
165+
{"FH", halfSizeString},
166+
{"HH", halfSizeString},
167+
{"TH", halfSizeString},
168+
},
169+
},
170+
{
171+
// Tuples containing adaptive columns should be independent of how the tuple was created.
172+
// And adaptive values are always outlined starting from the left.
173+
// This means that in a table with two adaptive columns where both columns were previously stored out-of line,
174+
// Decreasing the size of the second column may allow both columns to be stored inline.
175+
Query: "UPDATE blobt2 SET b2 = LOAD_FILE('testdata/tinyFile') WHERE i = 'HH'",
176+
},
177+
{
178+
Query: "select i, b1, b2 from blobt2 where i = 'HH'",
179+
Expected: []sql.Row{{"HH", halfSizeString, tinyString}},
180+
},
181+
{
182+
// Similar to the above, dropping a column can change whether the other column is inlined.
183+
Query: "ALTER TABLE blobt2 DROP COLUMN b2",
184+
},
185+
{
186+
Query: "select i, b1 from blobt2",
187+
Expected: []sql.Row{
188+
{"FF", fullSizeString},
189+
{"HF", halfSizeString},
190+
{"TF", tinyString},
191+
{"FH", fullSizeString},
192+
{"HH", halfSizeString},
193+
{"TH", tinyString},
194+
{"FT", fullSizeString},
195+
{"HT", halfSizeString},
196+
{"TT", tinyString},
197+
},
198+
},
199+
},
200+
},
201+
})
202+
})
203+
}
204+
}
205+
206+
func TestAdaptiveEncodingVarbit(t *testing.T) {
207+
columnType := "varbit"
208+
fullSizeOutOfLineRepr := fullSizeVarbit
54209
RunScripts(t, []ScriptTest{
55210
{
56211
Name: "Adaptive Encoding With One Column",
57212
SetUpScript: setup.SetupScript{
58213
fmt.Sprintf(`create table blobt (i char(1) primary key, b %s);`, columnType),
59214
fmt.Sprintf(`create table blobt2 (i char(2) primary key, b1 %s, b2 %s);`, columnType, columnType),
60215
`insert into blobt values
61-
('F', LOAD_FILE('testdata/fullSize')),
62-
('H', LOAD_FILE('testdata/halfSize')),
63-
('T', LOAD_FILE('testdata/tinyFile'))`,
216+
('F', LOAD_FILE('testdata/fullSizeVarbit')),
217+
('H', LOAD_FILE('testdata/halfSizeVarbit')),
218+
('T', LOAD_FILE('testdata/tinyFileVarbit'))`,
64219
},
65220
Assertions: []ScriptTestAssertion{
66221
{
67222
Query: "select b from blobt where i = 'F'",
68-
Expected: []sql.Row{{fullSizeString}},
223+
Expected: []sql.Row{{fullSizeVarbit}},
69224
},
70225
{
71226
// Files that can fit within a tuple are stored inline.
72227
Query: "select b from blobt where i = 'H'",
73-
Expected: []sql.Row{{halfSizeString}},
228+
Expected: []sql.Row{{halfSizeVarbit}},
74229
},
75230
{
76231
// An inlined adaptive column can be used in a filter.
77-
Query: "select i from blobt where b = LOAD_FILE('testdata/fullSize')",
232+
Query: "select i from blobt where b = LOAD_FILE('testdata/fullSizeVarbit')",
78233
Expected: []sql.Row{{"F"}},
79234
},
80235
{
81236
// An out-of-line adaptive column can be used in a filter.
82-
Query: "select i from blobt where b = LOAD_FILE('testdata/halfSize')",
237+
Query: "select i from blobt where b = LOAD_FILE('testdata/halfSizeVarbit')",
83238
Expected: []sql.Row{{"H"}},
84239
},
85240
},
@@ -105,15 +260,15 @@ func TestAdaptiveEncoding(t *testing.T) {
105260
// However, strings smaller than the address size (20 bytes) are never stored out-of-band.
106261
Query: "select i, b1, b2 from blobt2",
107262
Expected: []sql.Row{
108-
{"FF", fullSizeString, fullSizeString},
109-
{"HF", halfSizeString, fullSizeString},
110-
{"TF", tinyString, fullSizeString},
111-
{"FH", fullSizeString, halfSizeString},
112-
{"HH", halfSizeString, halfSizeString},
113-
{"TH", tinyString, halfSizeString},
114-
{"FT", fullSizeString, tinyString},
115-
{"HT", halfSizeString, tinyString},
116-
{"TT", tinyString, tinyString},
263+
{"FF", fullSizeVarbit, fullSizeVarbit},
264+
{"HF", halfSizeVarbit, fullSizeVarbit},
265+
{"TF", tinyVarbit, fullSizeVarbit},
266+
{"FH", fullSizeVarbit, halfSizeVarbit},
267+
{"HH", halfSizeVarbit, halfSizeVarbit},
268+
{"TH", tinyVarbit, halfSizeVarbit},
269+
{"FT", fullSizeVarbit, tinyVarbit},
270+
{"HT", halfSizeVarbit, tinyVarbit},
271+
{"TT", tinyVarbit, tinyVarbit},
117272
},
118273
},
119274
{
@@ -145,9 +300,9 @@ func TestAdaptiveEncoding(t *testing.T) {
145300
{
146301
Query: "select i, b2 FROM blobt2 WHERE b2 LIKE '\x02%'",
147302
Expected: []sql.Row{
148-
{"FH", halfSizeString},
149-
{"HH", halfSizeString},
150-
{"TH", halfSizeString},
303+
{"FH", halfSizeVarbit},
304+
{"HH", halfSizeVarbit},
305+
{"TH", halfSizeVarbit},
151306
},
152307
},
153308
{
@@ -159,7 +314,7 @@ func TestAdaptiveEncoding(t *testing.T) {
159314
},
160315
{
161316
Query: "select i, b1, b2 from blobt2 where i = 'HH'",
162-
Expected: []sql.Row{{"HH", halfSizeString, tinyString}},
317+
Expected: []sql.Row{{"HH", halfSizeVarbit, tinyVarbit}},
163318
},
164319
{
165320
// Similar to the above, dropping a column can change whether the other column is inlined.
@@ -168,15 +323,15 @@ func TestAdaptiveEncoding(t *testing.T) {
168323
{
169324
Query: "select i, b1 from blobt2",
170325
Expected: []sql.Row{
171-
{"FF", fullSizeString},
172-
{"HF", halfSizeString},
173-
{"TF", tinyString},
174-
{"FH", fullSizeString},
175-
{"HH", halfSizeString},
176-
{"TH", tinyString},
177-
{"FT", fullSizeString},
178-
{"HT", halfSizeString},
179-
{"TT", tinyString},
326+
{"FF", fullSizeVarbit},
327+
{"HF", halfSizeVarbit},
328+
{"TF", tinyVarbit},
329+
{"FH", fullSizeVarbit},
330+
{"HH", halfSizeVarbit},
331+
{"TH", tinyVarbit},
332+
{"FT", fullSizeVarbit},
333+
{"HT", halfSizeVarbit},
334+
{"TT", tinyVarbit},
180335
},
181336
},
182337
},

testing/go/types_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,36 @@ var typesTests = []ScriptTest{
316316
{2, pgtype.Bits{Bytes: []uint8{0x2b, 0x55}, Len: 16, Valid: true}},
317317
},
318318
},
319+
{
320+
Query: "INSERT INTO t_bit_varying VALUES (3, B'101010101010101010');",
321+
ExpectedErr: "bit string too long for type bit varying(16)",
322+
},
323+
},
324+
},
325+
{
326+
Name: "Bit varying type, unbounded",
327+
Focus: true,
328+
SetUpScript: []string{
329+
"CREATE TABLE t_bit_varying (id INTEGER primary key, v1 BIT VARYING);",
330+
"INSERT INTO t_bit_varying VALUES (1, B'1101101010101010'), (2, B'0010101101010101');",
331+
},
332+
Assertions: []ScriptTestAssertion{
333+
{
334+
Query: "SELECT * FROM t_bit_varying ORDER BY id;",
335+
Expected: []sql.Row{
336+
{1, pgtype.Bits{Bytes: []uint8{0xda, 0xaa}, Len: 16, Valid: true}},
337+
{2, pgtype.Bits{Bytes: []uint8{0x2b, 0x55}, Len: 16, Valid: true}},
338+
},
339+
},
340+
{
341+
Query: "INSERT INTO t_bit_varying VALUES (3, B'101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010');",
342+
},
343+
{
344+
Query: "SELECT * FROM t_bit_varying WHERE id = 3 order by 1;",
345+
Expected: []sql.Row{
346+
{3, pgtype.Bits{Bytes: []uint8{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0}, Len: 108, Valid: true}},
347+
},
348+
},
319349
},
320350
},
321351
{

0 commit comments

Comments
 (0)