package pgtype
import (
)
type arrayHeader struct {
ContainsNull bool
ElementOID uint32
Dimensions []ArrayDimension
}
type ArrayDimension struct {
Length int32
LowerBound int32
}
func ( []ArrayDimension) int {
if len() == 0 {
return 0
}
:= int([0].Length)
for , := range [1:] {
*= int(.Length)
}
if < 0 {
return 0
}
return
}
func ( *arrayHeader) ( *Map, []byte) (int, error) {
if len() < 12 {
return 0, fmt.Errorf("array header too short: %d", len())
}
:= 0
:= int(binary.BigEndian.Uint32([:]))
+= 4
if > 6 {
return 0, fmt.Errorf("array has too many dimensions: %d", )
}
.ContainsNull = binary.BigEndian.Uint32([:]) == 1
+= 4
.ElementOID = binary.BigEndian.Uint32([:])
+= 4
if len() < 12+*8 {
return 0, fmt.Errorf("array header too short for %d dimensions: %d", , len())
}
.Dimensions = make([]ArrayDimension, )
for := range .Dimensions {
.Dimensions[].Length = int32(binary.BigEndian.Uint32([:]))
+= 4
.Dimensions[].LowerBound = int32(binary.BigEndian.Uint32([:]))
+= 4
}
return , nil
}
func ( arrayHeader) ( []byte) []byte {
= pgio.AppendInt32(, int32(len(.Dimensions)))
var int32
if .ContainsNull {
= 1
}
= pgio.AppendInt32(, )
= pgio.AppendUint32(, .ElementOID)
for := range .Dimensions {
= pgio.AppendInt32(, .Dimensions[].Length)
= pgio.AppendInt32(, .Dimensions[].LowerBound)
}
return
}
type untypedTextArray struct {
Elements []string
Quoted []bool
Dimensions []ArrayDimension
}
func ( string) (*untypedTextArray, error) {
:= &untypedTextArray{
Elements: []string{},
Quoted: []bool{},
Dimensions: []ArrayDimension{},
}
:= bytes.NewBufferString()
skipWhitespace()
, , := .ReadRune()
if != nil {
return nil, fmt.Errorf("invalid array: %w", )
}
var []ArrayDimension
if == '[' {
.UnreadRune()
for {
, _, = .ReadRune()
if != nil {
return nil, fmt.Errorf("invalid array: %w", )
}
if == '=' {
break
} else if != '[' {
return nil, fmt.Errorf("invalid array, expected '[' or '=' got %v", )
}
, := arrayParseInteger()
if != nil {
return nil, fmt.Errorf("invalid array: %w", )
}
, _, = .ReadRune()
if != nil {
return nil, fmt.Errorf("invalid array: %w", )
}
if != ':' {
return nil, fmt.Errorf("invalid array, expected ':' got %v", )
}
, := arrayParseInteger()
if != nil {
return nil, fmt.Errorf("invalid array: %w", )
}
, _, = .ReadRune()
if != nil {
return nil, fmt.Errorf("invalid array: %w", )
}
if != ']' {
return nil, fmt.Errorf("invalid array, expected ']' got %v", )
}
= append(, ArrayDimension{LowerBound: , Length: - + 1})
}
, _, = .ReadRune()
if != nil {
return nil, fmt.Errorf("invalid array: %w", )
}
}
if != '{' {
return nil, fmt.Errorf("invalid array, expected '{' got %v", )
}
:= []ArrayDimension{{LowerBound: 1, Length: 0}}
for {
, _, = .ReadRune()
if != nil {
return nil, fmt.Errorf("invalid array: %w", )
}
if == '{' {
[len()-1].Length = 1
= append(, ArrayDimension{LowerBound: 1})
} else {
.UnreadRune()
break
}
}
:= len() - 1
:=
for {
, _, = .ReadRune()
if != nil {
return nil, fmt.Errorf("invalid array: %w", )
}
switch {
case '{':
if == {
[].Length++
}
++
case ',':
case '}':
--
if < {
=
}
default:
.UnreadRune()
, , := arrayParseValue()
if != nil {
return nil, fmt.Errorf("invalid array value: %w", )
}
if == {
[].Length++
}
.Quoted = append(.Quoted, )
.Elements = append(.Elements, )
}
if < 0 {
break
}
}
skipWhitespace()
if .Len() > 0 {
return nil, fmt.Errorf("unexpected trailing data: %v", .String())
}
if len(.Elements) == 0 {
} else if len() > 0 {
.Dimensions =
} else {
.Dimensions =
}
return , nil
}
func ( *bytes.Buffer) {
var rune
var error
for , _, _ = .ReadRune(); unicode.IsSpace(); , _, _ = .ReadRune() {
}
if != io.EOF {
.UnreadRune()
}
}
func ( *bytes.Buffer) (string, bool, error) {
, , := .ReadRune()
if != nil {
return "", false,
}
if == '"' {
return arrayParseQuotedValue()
}
.UnreadRune()
:= &bytes.Buffer{}
for {
, , := .ReadRune()
if != nil {
return "", false,
}
switch {
case ',', '}':
.UnreadRune()
return .String(), false, nil
}
.WriteRune()
}
}
func ( *bytes.Buffer) (string, bool, error) {
:= &bytes.Buffer{}
for {
, , := .ReadRune()
if != nil {
return "", false,
}
switch {
case '\\':
, _, = .ReadRune()
if != nil {
return "", false,
}
case '"':
_, _, = .ReadRune()
if != nil {
return "", false,
}
.UnreadRune()
return .String(), true, nil
}
.WriteRune()
}
}
func ( *bytes.Buffer) (int32, error) {
:= &bytes.Buffer{}
for {
, , := .ReadRune()
if != nil {
return 0,
}
if ('0' <= && <= '9') || == '-' {
.WriteRune()
} else {
.UnreadRune()
, := strconv.ParseInt(.String(), 10, 32)
if != nil {
return 0,
}
return int32(), nil
}
}
}
func ( []byte, []ArrayDimension) []byte {
var bool
for , := range {
if .LowerBound != 1 {
= true
}
}
if ! {
return
}
for , := range {
= append(, '[')
= append(, strconv.FormatInt(int64(.LowerBound), 10)...)
= append(, ':')
= append(, strconv.FormatInt(int64(.LowerBound+.Length-1), 10)...)
= append(, ']')
}
return append(, '=')
}
var quoteArrayReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)
func ( string) string {
return `"` + quoteArrayReplacer.Replace() + `"`
}
func ( byte) bool {
return == ' ' || == '\t' || == '\n' || == '\r' || == '\v' || == '\f'
}
func ( string) string {
if == "" || (len() == 4 && strings.EqualFold(, "null")) || isSpace([0]) || isSpace([len()-1]) || strings.ContainsAny(, `{},"\`) {
return quoteArrayElement()
}
return
}
type Array[ any] struct {
Elements []
Dims []ArrayDimension
Valid bool
}
func ( Array[]) () []ArrayDimension {
return .Dims
}
func ( Array[]) ( int) any {
return .Elements[]
}
func ( Array[]) () any {
var
return
}
func ( *Array[]) ( []ArrayDimension) error {
if == nil {
* = Array[]{}
return nil
}
:= cardinality()
* = Array[]{
Elements: make([], ),
Dims: ,
Valid: true,
}
return nil
}
func ( Array[]) ( int) any {
return &.Elements[]
}
func ( Array[]) () any {
return new()
}
type FlatArray[ any] []
func ( FlatArray[]) () []ArrayDimension {
if == nil {
return nil
}
return []ArrayDimension{{Length: int32(len()), LowerBound: 1}}
}
func ( FlatArray[]) ( int) any {
return []
}
func ( FlatArray[]) () any {
var
return
}
func ( *FlatArray[]) ( []ArrayDimension) error {
if == nil {
* = nil
return nil
}
:= cardinality()
* = make(FlatArray[], )
return nil
}
func ( FlatArray[]) ( int) any {
return &[]
}
func ( FlatArray[]) () any {
return new()
}