Skip to content

Commit 26709a6

Browse files
committed
Length checking for inserted bit values
1 parent 53660c4 commit 26709a6

4 files changed

Lines changed: 36 additions & 10 deletions

File tree

server/functions/bit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ var bitin = framework.Function3{
5252

5353
expectedLength := pgtypes.GetCharLengthFromTypmod(typmod)
5454
if array.BitLen() != uint(expectedLength) {
55-
return nil, pgtypes.ErrInvalidSyntaxForType.New("bit", input)
55+
return nil, pgtypes.ErrWrongLengthBit.New(len(input), expectedLength)
5656
}
5757

5858
return array, nil

server/functions/framework/cast.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,13 @@ func GetAssignmentCast(fromType *pgtypes.DoltgresType, toType *pgtypes.DoltgresT
174174
}
175175
// We check for the identity after checking the maps, as the identity may be overridden (such as for types that have
176176
// parameters). If the "to" type is a string type, then we do not use the identity, and use the I/O conversion below.
177-
if fromType.ID == toType.ID && fromType.TypCategory != pgtypes.TypeCategory_StringTypes {
177+
if fromType.ID == toType.ID && fromType.TypCategory != pgtypes.TypeCategory_StringTypes && fromType.TypCategory != pgtypes.TypeCategory_BitStringTypes {
178178
return IdentityCast
179179
}
180+
180181
// All types have a built-in assignment cast to string types: https://www.postgresql.org/docs/15/sql-createcast.html
182+
// This is also where length checks occur for types like char(n), varchar(n), bit(n), etc., which is not great
183+
// TODO: move length checks to their own analyzer step
181184
if toType.TypCategory == pgtypes.TypeCategory_StringTypes {
182185
return func(ctx *sql.Context, val any, targetType *pgtypes.DoltgresType) (any, error) {
183186
if val == nil {
@@ -189,6 +192,17 @@ func GetAssignmentCast(fromType *pgtypes.DoltgresType, toType *pgtypes.DoltgresT
189192
}
190193
return targetType.IoInput(ctx, str)
191194
}
195+
} else if toType.TypCategory == pgtypes.TypeCategory_BitStringTypes {
196+
return func(ctx *sql.Context, val any, targetType *pgtypes.DoltgresType) (any, error) {
197+
if val == nil {
198+
return nil, nil
199+
}
200+
str, err := fromType.IoOutput(ctx, val)
201+
if err != nil {
202+
return nil, err
203+
}
204+
return targetType.IoInput(ctx, str)
205+
}
192206
}
193207
return nil
194208
}
@@ -209,8 +223,8 @@ func GetImplicitCast(fromType *pgtypes.DoltgresType, toType *pgtypes.DoltgresTyp
209223

210224
// addTypeCast registers the given type cast.
211225
func addTypeCast(mutex *sync.RWMutex,
212-
castMap map[id.Type]map[id.Type]pgtypes.TypeCastFunction,
213-
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 {
214228
mutex.Lock()
215229
defer mutex.Unlock()
216230

@@ -240,8 +254,8 @@ func getPotentialCasts(mutex *sync.RWMutex, castArray map[id.Type][]*pgtypes.Dol
240254
// getCast returns the type cast function that will cast the "from" type to the "to" type. Returns nil if such a cast is
241255
// not valid.
242256
func getCast(mutex *sync.RWMutex,
243-
castMap map[id.Type]map[id.Type]pgtypes.TypeCastFunction,
244-
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 {
245259
mutex.RLock()
246260
defer mutex.RUnlock()
247261

server/types/bit.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ package types
1616

1717
import (
1818
"github.com/dolthub/doltgresql/core/id"
19+
"gopkg.in/src-d/go-errors.v1"
1920
)
2021

22+
// ErrWrongLengthBit is returned when a value with the incorrect length is inserted into a Bit column.
23+
var ErrWrongLengthBit = errors.NewKind(`bit string length %d does not match type bit(%d)`)
24+
2125
// Bit is a fixed-length bit string.
2226
var Bit = &DoltgresType{
2327
ID: toInternal("bit"),

testing/go/types_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ var typesTests = []ScriptTest{
8080
},
8181
{
8282
Name: "Bit type",
83-
Focus: true, // no pgx support: unknown type with oid: 1560
83+
Focus: true,
8484
SetUpScript: []string{
8585
"CREATE TABLE t_bit (id INTEGER primary key, v1 BIT(8));",
8686
"INSERT INTO t_bit VALUES (1, B'11011010'), (2, B'00101011');",
@@ -93,11 +93,19 @@ var typesTests = []ScriptTest{
9393
{2, pgtype.Bits{Bytes: []uint8{0x2b}, Len: 8, Valid: true}},
9494
},
9595
},
96+
{
97+
Query: "INSERT INTO t_bit VALUES (3, B'101');",
98+
ExpectedErr: "bit string length 3 does not match type bit(8)",
99+
},
100+
{
101+
Query: "INSERT INTO t_bit VALUES (3, B'1001000110');",
102+
ExpectedErr: "bit string length 10 does not match type bit(8)",
103+
},
96104
},
97105
},
98106
{
99107
Name: "Bit key",
100-
Skip: true, // no pgx support: unknown type with oid: 1560
108+
Skip: true, // no comparator in serialization layer
101109
SetUpScript: []string{
102110
"CREATE TABLE t_bit (id BIT(8) primary key, v1 BIT(8));",
103111
"INSERT INTO t_bit VALUES (B'11011010', B'11011010'), (B'00101011', B'00101011');",
@@ -3009,8 +3017,8 @@ var typesTests = []ScriptTest{
30093017
"create table t_uuid2 (id int primary key, v1 uuid, v2 uuid);",
30103018
"create index on t_uuid2(v1, v2);",
30113019
"insert into t_uuid2 values " +
3012-
"(1, 'f47ac10b58cc4372a567-0e02b2c3d479', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'), " +
3013-
"(2, 'dcf783c8-49c2-44b4-8b90-34ad8c52ea1e', 'f99802e8-0018-4913-806c-bcad5d246d46');",
3020+
"(1, 'f47ac10b58cc4372a567-0e02b2c3d479', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'), " +
3021+
"(2, 'dcf783c8-49c2-44b4-8b90-34ad8c52ea1e', 'f99802e8-0018-4913-806c-bcad5d246d46');",
30143022
},
30153023
Assertions: []ScriptTestAssertion{
30163024
{

0 commit comments

Comments
 (0)