package pgtype
import (
)
type MultirangeGetter interface {
IsNull() bool
Len() int
Index(i int) any
IndexType() any
}
type MultirangeSetter interface {
ScanNull() error
SetLen(n int) error
ScanIndex(i int) any
ScanIndexType() any
}
type MultirangeCodec struct {
ElementType *Type
}
func ( *MultirangeCodec) ( int16) bool {
return .ElementType.Codec.FormatSupported()
}
func ( *MultirangeCodec) () int16 {
return .ElementType.Codec.PreferredFormat()
}
func ( *MultirangeCodec) ( *Map, uint32, int16, any) EncodePlan {
, := .(MultirangeGetter)
if ! {
return nil
}
:= .IndexType()
:= .PlanEncode(.ElementType.OID, , )
if == nil {
return nil
}
switch {
case BinaryFormatCode:
return &encodePlanMultirangeCodecBinary{ac: , m: , oid: }
case TextFormatCode:
return &encodePlanMultirangeCodecText{ac: , m: , oid: }
}
return nil
}
type encodePlanMultirangeCodecText struct {
ac *MultirangeCodec
m *Map
oid uint32
}
func ( *encodePlanMultirangeCodecText) ( any, []byte) ( []byte, error) {
:= .(MultirangeGetter)
if .IsNull() {
return nil, nil
}
:= .Len()
= append(, '{')
var EncodePlan
var reflect.Type
:= make([]byte, 0, 32)
for := range {
if > 0 {
= append(, ',')
}
:= .Index()
var []byte
if != nil {
:= reflect.TypeOf()
if != {
=
= .m.PlanEncode(.ac.ElementType.OID, TextFormatCode, )
if == nil {
return nil, fmt.Errorf("unable to encode %v", .Index())
}
}
, = .Encode(, )
if != nil {
return nil,
}
}
if == nil {
return nil, fmt.Errorf("multirange cannot contain NULL element")
} else {
= append(, ...)
}
}
= append(, '}')
return , nil
}
type encodePlanMultirangeCodecBinary struct {
ac *MultirangeCodec
m *Map
oid uint32
}
func ( *encodePlanMultirangeCodecBinary) ( any, []byte) ( []byte, error) {
:= .(MultirangeGetter)
if .IsNull() {
return nil, nil
}
:= .Len()
= pgio.AppendInt32(, int32())
var EncodePlan
var reflect.Type
for := range {
:= len()
= pgio.AppendInt32(, -1)
:= .Index()
var []byte
if != nil {
:= reflect.TypeOf()
if != {
=
= .m.PlanEncode(.ac.ElementType.OID, BinaryFormatCode, )
if == nil {
return nil, fmt.Errorf("unable to encode %v", .Index())
}
}
, = .Encode(, )
if != nil {
return nil,
}
}
if == nil {
return nil, fmt.Errorf("multirange cannot contain NULL element")
} else {
=
pgio.SetInt32([:], int32(len([:])-4))
}
}
return , nil
}
func ( *MultirangeCodec) ( *Map, uint32, int16, any) ScanPlan {
, := .(MultirangeSetter)
if ! {
return nil
}
:= .ScanIndexType()
:= .PlanScan(.ElementType.OID, , )
if , := .(*scanPlanFail); {
return nil
}
return &scanPlanMultirangeCodec{
multirangeCodec: ,
m: ,
oid: ,
formatCode: ,
}
}
func ( *MultirangeCodec) ( *Map, uint32, []byte, MultirangeSetter) error {
:= 0
:= int(binary.BigEndian.Uint32([:]))
+= 4
if > len()/4 {
return fmt.Errorf("multirange element count %d exceeds available data", )
}
:= .SetLen()
if != nil {
return
}
if == 0 {
return nil
}
:= .ElementType.Codec.PlanScan(, .ElementType.OID, BinaryFormatCode, .ScanIndex(0))
if == nil {
= .PlanScan(.ElementType.OID, BinaryFormatCode, .ScanIndex(0))
}
for := range {
:= .ScanIndex()
:= int(int32(binary.BigEndian.Uint32([:])))
+= 4
var []byte
if >= 0 {
= [ : +]
+=
}
= .Scan(, )
if != nil {
return fmt.Errorf("failed to scan multirange element %d: %w", , )
}
}
return nil
}
func ( *MultirangeCodec) ( *Map, uint32, []byte, MultirangeSetter) error {
, := parseUntypedTextMultirange()
if != nil {
return
}
= .SetLen(len())
if != nil {
return
}
if len() == 0 {
return nil
}
:= .ElementType.Codec.PlanScan(, .ElementType.OID, TextFormatCode, .ScanIndex(0))
if == nil {
= .PlanScan(.ElementType.OID, TextFormatCode, .ScanIndex(0))
}
for , := range {
:= .ScanIndex()
= .Scan([]byte(), )
if != nil {
return
}
}
return nil
}
type scanPlanMultirangeCodec struct {
multirangeCodec *MultirangeCodec
m *Map
oid uint32
formatCode int16
elementScanPlan ScanPlan
}
func ( *scanPlanMultirangeCodec) ( []byte, any) error {
:= .multirangeCodec
:= .m
:= .oid
:= .formatCode
:= .(MultirangeSetter)
if == nil {
return .ScanNull()
}
switch {
case BinaryFormatCode:
return .decodeBinary(, , , )
case TextFormatCode:
return .decodeText(, , , )
default:
return fmt.Errorf("unknown format code %d", )
}
}
func ( *MultirangeCodec) ( *Map, uint32, int16, []byte) (driver.Value, error) {
if == nil {
return nil, nil
}
switch {
case TextFormatCode:
return string(), nil
case BinaryFormatCode:
:= make([]byte, len())
copy(, )
return , nil
default:
return nil, fmt.Errorf("unknown format code %d", )
}
}
func ( *MultirangeCodec) ( *Map, uint32, int16, []byte) (any, error) {
if == nil {
return nil, nil
}
var Multirange[Range[any]]
:= .PlanScan(, , &).Scan(, &)
return ,
}
func ( []byte) ([]string, error) {
:= make([]string, 0)
:= bytes.NewBuffer()
skipWhitespace()
, , := .ReadRune()
if != nil {
return nil, fmt.Errorf("invalid array: %w", )
}
if != '{' {
return nil, fmt.Errorf("invalid multirange, expected '{' got %v", )
}
:
for {
, _, = .ReadRune()
if != nil {
return nil, fmt.Errorf("invalid multirange: %w", )
}
switch {
case ',':
case '}':
break
default:
.UnreadRune()
, := parseRange()
if != nil {
return nil, fmt.Errorf("invalid multirange value: %w", )
}
= append(, )
}
}
skipWhitespace()
if .Len() > 0 {
return nil, fmt.Errorf("unexpected trailing data: %v", .String())
}
return , nil
}
func ( *bytes.Buffer) (string, error) {
:= &bytes.Buffer{}
:= false
for {
, , := .ReadRune()
if != nil {
return "",
}
switch {
case ',', '}':
if == ',' && ! {
= true
break
}
.UnreadRune()
return .String(), nil
}
.WriteRune()
}
}
type Multirange[ RangeValuer] []
func ( Multirange[]) () bool {
return == nil
}
func ( Multirange[]) () int {
return len()
}
func ( Multirange[]) ( int) any {
return []
}
func ( Multirange[]) () any {
var
return
}
func ( *Multirange[]) () error {
* = nil
return nil
}
func ( *Multirange[]) ( int) error {
* = make([], )
return nil
}
func ( Multirange[]) ( int) any {
return &[]
}
func ( Multirange[]) () any {
return new()
}