mirror of https://github.com/jackc/pgx.git
323 lines
6.1 KiB
Go
323 lines
6.1 KiB
Go
package pgtype
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
)
|
|
|
|
type BoundType byte
|
|
|
|
const (
|
|
Inclusive = BoundType('i')
|
|
Exclusive = BoundType('e')
|
|
Unbounded = BoundType('U')
|
|
Empty = BoundType('E')
|
|
)
|
|
|
|
func (bt BoundType) String() string {
|
|
return string(bt)
|
|
}
|
|
|
|
type untypedTextRange struct {
|
|
Lower string
|
|
Upper string
|
|
LowerType BoundType
|
|
UpperType BoundType
|
|
}
|
|
|
|
func parseUntypedTextRange(src string) (*untypedTextRange, error) {
|
|
utr := &untypedTextRange{}
|
|
if src == "empty" {
|
|
utr.LowerType = Empty
|
|
utr.UpperType = Empty
|
|
return utr, nil
|
|
}
|
|
|
|
buf := bytes.NewBufferString(src)
|
|
|
|
skipWhitespace(buf)
|
|
|
|
r, _, err := buf.ReadRune()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid lower bound: %w", err)
|
|
}
|
|
switch r {
|
|
case '(':
|
|
utr.LowerType = Exclusive
|
|
case '[':
|
|
utr.LowerType = Inclusive
|
|
default:
|
|
return nil, fmt.Errorf("missing lower bound, instead got: %v", string(r))
|
|
}
|
|
|
|
r, _, err = buf.ReadRune()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid lower value: %w", err)
|
|
}
|
|
buf.UnreadRune()
|
|
|
|
if r == ',' {
|
|
utr.LowerType = Unbounded
|
|
} else {
|
|
utr.Lower, err = rangeParseValue(buf)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid lower value: %w", err)
|
|
}
|
|
}
|
|
|
|
r, _, err = buf.ReadRune()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("missing range separator: %w", err)
|
|
}
|
|
if r != ',' {
|
|
return nil, fmt.Errorf("missing range separator: %v", r)
|
|
}
|
|
|
|
r, _, err = buf.ReadRune()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid upper value: %w", err)
|
|
}
|
|
|
|
if r == ')' || r == ']' {
|
|
utr.UpperType = Unbounded
|
|
} else {
|
|
buf.UnreadRune()
|
|
utr.Upper, err = rangeParseValue(buf)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid upper value: %w", err)
|
|
}
|
|
|
|
r, _, err = buf.ReadRune()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("missing upper bound: %w", err)
|
|
}
|
|
switch r {
|
|
case ')':
|
|
utr.UpperType = Exclusive
|
|
case ']':
|
|
utr.UpperType = Inclusive
|
|
default:
|
|
return nil, fmt.Errorf("missing upper bound, instead got: %v", string(r))
|
|
}
|
|
}
|
|
|
|
skipWhitespace(buf)
|
|
|
|
if buf.Len() > 0 {
|
|
return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
|
|
}
|
|
|
|
return utr, nil
|
|
}
|
|
|
|
func rangeParseValue(buf *bytes.Buffer) (string, error) {
|
|
r, _, err := buf.ReadRune()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if r == '"' {
|
|
return rangeParseQuotedValue(buf)
|
|
}
|
|
buf.UnreadRune()
|
|
|
|
s := &bytes.Buffer{}
|
|
|
|
for {
|
|
r, _, err := buf.ReadRune()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
switch r {
|
|
case '\\':
|
|
r, _, err = buf.ReadRune()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
case ',', '[', ']', '(', ')':
|
|
buf.UnreadRune()
|
|
return s.String(), nil
|
|
}
|
|
|
|
s.WriteRune(r)
|
|
}
|
|
}
|
|
|
|
func rangeParseQuotedValue(buf *bytes.Buffer) (string, error) {
|
|
s := &bytes.Buffer{}
|
|
|
|
for {
|
|
r, _, err := buf.ReadRune()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
switch r {
|
|
case '\\':
|
|
r, _, err = buf.ReadRune()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
case '"':
|
|
r, _, err = buf.ReadRune()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if r != '"' {
|
|
buf.UnreadRune()
|
|
return s.String(), nil
|
|
}
|
|
}
|
|
s.WriteRune(r)
|
|
}
|
|
}
|
|
|
|
type untypedBinaryRange struct {
|
|
Lower []byte
|
|
Upper []byte
|
|
LowerType BoundType
|
|
UpperType BoundType
|
|
}
|
|
|
|
// 0 = () = 00000
|
|
// 1 = empty = 00001
|
|
// 2 = [) = 00010
|
|
// 4 = (] = 00100
|
|
// 6 = [] = 00110
|
|
// 8 = ) = 01000
|
|
// 12 = ] = 01100
|
|
// 16 = ( = 10000
|
|
// 18 = [ = 10010
|
|
// 24 = = 11000
|
|
|
|
const emptyMask = 1
|
|
const lowerInclusiveMask = 2
|
|
const upperInclusiveMask = 4
|
|
const lowerUnboundedMask = 8
|
|
const upperUnboundedMask = 16
|
|
|
|
func parseUntypedBinaryRange(src []byte) (*untypedBinaryRange, error) {
|
|
ubr := &untypedBinaryRange{}
|
|
|
|
if len(src) == 0 {
|
|
return nil, fmt.Errorf("range too short: %v", len(src))
|
|
}
|
|
|
|
rangeType := src[0]
|
|
rp := 1
|
|
|
|
if rangeType&emptyMask > 0 {
|
|
if len(src[rp:]) > 0 {
|
|
return nil, fmt.Errorf("unexpected trailing bytes parsing empty range: %v", len(src[rp:]))
|
|
}
|
|
ubr.LowerType = Empty
|
|
ubr.UpperType = Empty
|
|
return ubr, nil
|
|
}
|
|
|
|
if rangeType&lowerInclusiveMask > 0 {
|
|
ubr.LowerType = Inclusive
|
|
} else if rangeType&lowerUnboundedMask > 0 {
|
|
ubr.LowerType = Unbounded
|
|
} else {
|
|
ubr.LowerType = Exclusive
|
|
}
|
|
|
|
if rangeType&upperInclusiveMask > 0 {
|
|
ubr.UpperType = Inclusive
|
|
} else if rangeType&upperUnboundedMask > 0 {
|
|
ubr.UpperType = Unbounded
|
|
} else {
|
|
ubr.UpperType = Exclusive
|
|
}
|
|
|
|
if ubr.LowerType == Unbounded && ubr.UpperType == Unbounded {
|
|
if len(src[rp:]) > 0 {
|
|
return nil, fmt.Errorf("unexpected trailing bytes parsing unbounded range: %v", len(src[rp:]))
|
|
}
|
|
return ubr, nil
|
|
}
|
|
|
|
if len(src[rp:]) < 4 {
|
|
return nil, fmt.Errorf("too few bytes for size: %v", src[rp:])
|
|
}
|
|
valueLen := int(binary.BigEndian.Uint32(src[rp:]))
|
|
rp += 4
|
|
|
|
val := src[rp : rp+valueLen]
|
|
rp += valueLen
|
|
|
|
if ubr.LowerType != Unbounded {
|
|
ubr.Lower = val
|
|
} else {
|
|
ubr.Upper = val
|
|
if len(src[rp:]) > 0 {
|
|
return nil, fmt.Errorf("unexpected trailing bytes parsing range: %v", len(src[rp:]))
|
|
}
|
|
return ubr, nil
|
|
}
|
|
|
|
if ubr.UpperType != Unbounded {
|
|
if len(src[rp:]) < 4 {
|
|
return nil, fmt.Errorf("too few bytes for size: %v", src[rp:])
|
|
}
|
|
valueLen := int(binary.BigEndian.Uint32(src[rp:]))
|
|
rp += 4
|
|
ubr.Upper = src[rp : rp+valueLen]
|
|
rp += valueLen
|
|
}
|
|
|
|
if len(src[rp:]) > 0 {
|
|
return nil, fmt.Errorf("unexpected trailing bytes parsing range: %v", len(src[rp:]))
|
|
}
|
|
|
|
return ubr, nil
|
|
|
|
}
|
|
|
|
// Range is a generic range type.
|
|
type Range[T any] struct {
|
|
Lower T
|
|
Upper T
|
|
LowerType BoundType
|
|
UpperType BoundType
|
|
Valid bool
|
|
}
|
|
|
|
func (r Range[T]) IsNull() bool {
|
|
return !r.Valid
|
|
}
|
|
|
|
func (r Range[T]) BoundTypes() (lower, upper BoundType) {
|
|
return r.LowerType, r.UpperType
|
|
}
|
|
|
|
func (r Range[T]) Bounds() (lower, upper any) {
|
|
return &r.Lower, &r.Upper
|
|
}
|
|
|
|
func (r *Range[T]) ScanNull() error {
|
|
*r = Range[T]{}
|
|
return nil
|
|
}
|
|
|
|
func (r *Range[T]) ScanBounds() (lowerTarget, upperTarget any) {
|
|
return &r.Lower, &r.Upper
|
|
}
|
|
|
|
func (r *Range[T]) SetBoundTypes(lower, upper BoundType) error {
|
|
if lower == Unbounded || lower == Empty {
|
|
var zero T
|
|
r.Lower = zero
|
|
}
|
|
if upper == Unbounded || upper == Empty {
|
|
var zero T
|
|
r.Upper = zero
|
|
}
|
|
r.LowerType = lower
|
|
r.UpperType = upper
|
|
r.Valid = true
|
|
return nil
|
|
}
|