Temporarily remove range type support

query-exec-mode
Jack Christensen 2022-01-01 11:32:52 -06:00
parent d2cf33ed40
commit ffa1fdd66e
19 changed files with 8 additions and 3509 deletions

View File

@ -1,257 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgio"
)
type Daterange struct {
Lower Date
Upper Date
LowerType BoundType
UpperType BoundType
Valid bool
}
func (dst *Daterange) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Daterange{}
return nil
}
switch value := src.(type) {
case Daterange:
*dst = value
case *Daterange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to Daterange", src)
}
return nil
}
func (src Daterange) Get() interface{} {
if !src.Valid {
return nil
}
return src
}
func (src *Daterange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Daterange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Daterange{}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = Daterange{Valid: true}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *Daterange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Daterange{}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = Daterange{Valid: true}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src Daterange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src Daterange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Daterange) Scan(src interface{}) error {
if src == nil {
*dst = Daterange{}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Daterange) Value() (driver.Value, error) {
return EncodeValueText(src)
}

View File

@ -1,133 +0,0 @@
package pgtype_test
import (
"testing"
"time"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgtype/testutil"
)
func TestDaterangeTranscode(t *testing.T) {
testutil.TestSuccessfulTranscodeEqFunc(t, "daterange", []interface{}{
&pgtype.Daterange{LowerType: pgtype.Empty, UpperType: pgtype.Empty, Valid: true},
&pgtype.Daterange{
Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
&pgtype.Daterange{
Lower: pgtype.Date{Time: time.Date(1800, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Date{Time: time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
&pgtype.Daterange{},
}, func(aa, bb interface{}) bool {
a := aa.(pgtype.Daterange)
b := bb.(pgtype.Daterange)
return a.Valid == b.Valid &&
a.Lower.Time.Equal(b.Lower.Time) &&
a.Lower.Valid == b.Lower.Valid &&
a.Lower.InfinityModifier == b.Lower.InfinityModifier &&
a.Upper.Time.Equal(b.Upper.Time) &&
a.Upper.Valid == b.Upper.Valid &&
a.Upper.InfinityModifier == b.Upper.InfinityModifier
})
}
func TestDaterangeNormalize(t *testing.T) {
testutil.TestSuccessfulNormalizeEqFunc(t, []testutil.NormalizeTest{
{
SQL: "select daterange('2010-01-01', '2010-01-11', '(]')",
Value: pgtype.Daterange{
Lower: pgtype.Date{Time: time.Date(2010, 1, 2, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Date{Time: time.Date(2010, 1, 12, 0, 0, 0, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
},
}, func(aa, bb interface{}) bool {
a := aa.(pgtype.Daterange)
b := bb.(pgtype.Daterange)
return a.Valid == b.Valid &&
a.Lower.Time.Equal(b.Lower.Time) &&
a.Lower.Valid == b.Lower.Valid &&
a.Lower.InfinityModifier == b.Lower.InfinityModifier &&
a.Upper.Time.Equal(b.Upper.Time) &&
a.Upper.Valid == b.Upper.Valid &&
a.Upper.InfinityModifier == b.Upper.InfinityModifier
})
}
func TestDaterangeSet(t *testing.T) {
successfulTests := []struct {
source interface{}
result pgtype.Daterange
}{
{
source: nil,
result: pgtype.Daterange{},
},
{
source: &pgtype.Daterange{
Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
result: pgtype.Daterange{
Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
},
{
source: pgtype.Daterange{
Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
result: pgtype.Daterange{
Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
},
{
source: "[1990-12-31,2028-01-01)",
result: pgtype.Daterange{
Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
},
}
for i, tt := range successfulTests {
var r pgtype.Daterange
err := r.Set(tt.source)
if err != nil {
t.Errorf("%d: %v", i, err)
}
if r != tt.result {
t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
}
}
}

View File

@ -1,257 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgio"
)
type Int4range struct {
Lower Int4
Upper Int4
LowerType BoundType
UpperType BoundType
Valid bool
}
func (dst *Int4range) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int4range{}
return nil
}
switch value := src.(type) {
case Int4range:
*dst = value
case *Int4range:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to Int4range", src)
}
return nil
}
func (src Int4range) Get() interface{} {
if !src.Valid {
return nil
}
return src
}
func (src *Int4range) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Int4range) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4range{}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = Int4range{Valid: true}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *Int4range) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4range{}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = Int4range{Valid: true}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src Int4range) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src Int4range) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int4range) Scan(src interface{}) error {
if src == nil {
*dst = Int4range{}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int4range) Value() (driver.Value, error) {
return EncodeValueText(src)
}

View File

@ -1,28 +0,0 @@
package pgtype_test
import (
"testing"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgtype/testutil"
)
func TestInt4rangeTranscode(t *testing.T) {
testutil.TestSuccessfulTranscode(t, "int4range", []interface{}{
&pgtype.Int4range{LowerType: pgtype.Empty, UpperType: pgtype.Empty, Valid: true},
&pgtype.Int4range{Lower: pgtype.Int4{Int: 1, Valid: true}, Upper: pgtype.Int4{Int: 10, Valid: true}, LowerType: pgtype.Inclusive, UpperType: pgtype.Exclusive, Valid: true},
&pgtype.Int4range{Lower: pgtype.Int4{Int: -42, Valid: true}, Upper: pgtype.Int4{Int: -5, Valid: true}, LowerType: pgtype.Inclusive, UpperType: pgtype.Exclusive, Valid: true},
&pgtype.Int4range{Lower: pgtype.Int4{Int: 1, Valid: true}, LowerType: pgtype.Inclusive, UpperType: pgtype.Unbounded, Valid: true},
&pgtype.Int4range{Upper: pgtype.Int4{Int: 1, Valid: true}, LowerType: pgtype.Unbounded, UpperType: pgtype.Exclusive, Valid: true},
&pgtype.Int4range{},
})
}
func TestInt4rangeNormalize(t *testing.T) {
testutil.TestSuccessfulNormalize(t, []testutil.NormalizeTest{
{
SQL: "select int4range(1, 10, '(]')",
Value: pgtype.Int4range{Lower: pgtype.Int4{Int: 2, Valid: true}, Upper: pgtype.Int4{Int: 11, Valid: true}, LowerType: pgtype.Inclusive, UpperType: pgtype.Exclusive, Valid: true},
},
})
}

View File

@ -1,257 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgio"
)
type Int8range struct {
Lower Int8
Upper Int8
LowerType BoundType
UpperType BoundType
Valid bool
}
func (dst *Int8range) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int8range{}
return nil
}
switch value := src.(type) {
case Int8range:
*dst = value
case *Int8range:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to Int8range", src)
}
return nil
}
func (src Int8range) Get() interface{} {
if !src.Valid {
return nil
}
return src
}
func (src *Int8range) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Int8range) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8range{}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = Int8range{Valid: true}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *Int8range) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8range{}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = Int8range{Valid: true}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src Int8range) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src Int8range) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int8range) Scan(src interface{}) error {
if src == nil {
*dst = Int8range{}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int8range) Value() (driver.Value, error) {
return EncodeValueText(src)
}

View File

@ -1,28 +0,0 @@
package pgtype_test
import (
"testing"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgtype/testutil"
)
func TestInt8rangeTranscode(t *testing.T) {
testutil.TestSuccessfulTranscode(t, "Int8range", []interface{}{
&pgtype.Int8range{LowerType: pgtype.Empty, UpperType: pgtype.Empty, Valid: true},
&pgtype.Int8range{Lower: pgtype.Int8{Int: 1, Valid: true}, Upper: pgtype.Int8{Int: 10, Valid: true}, LowerType: pgtype.Inclusive, UpperType: pgtype.Exclusive, Valid: true},
&pgtype.Int8range{Lower: pgtype.Int8{Int: -42, Valid: true}, Upper: pgtype.Int8{Int: -5, Valid: true}, LowerType: pgtype.Inclusive, UpperType: pgtype.Exclusive, Valid: true},
&pgtype.Int8range{Lower: pgtype.Int8{Int: 1, Valid: true}, LowerType: pgtype.Inclusive, UpperType: pgtype.Unbounded, Valid: true},
&pgtype.Int8range{Upper: pgtype.Int8{Int: 1, Valid: true}, LowerType: pgtype.Unbounded, UpperType: pgtype.Exclusive, Valid: true},
&pgtype.Int8range{},
})
}
func TestInt8rangeNormalize(t *testing.T) {
testutil.TestSuccessfulNormalize(t, []testutil.NormalizeTest{
{
SQL: "select Int8range(1, 10, '(]')",
Value: pgtype.Int8range{Lower: pgtype.Int8{Int: 2, Valid: true}, Upper: pgtype.Int8{Int: 11, Valid: true}, LowerType: pgtype.Inclusive, UpperType: pgtype.Exclusive, Valid: true},
},
})
}

View File

@ -1,257 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgio"
)
type Numrange struct {
Lower Numeric
Upper Numeric
LowerType BoundType
UpperType BoundType
Valid bool
}
func (dst *Numrange) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Numrange{}
return nil
}
switch value := src.(type) {
case Numrange:
*dst = value
case *Numrange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to Numrange", src)
}
return nil
}
func (src Numrange) Get() interface{} {
if !src.Valid {
return nil
}
return src
}
func (src *Numrange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Numrange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Numrange{}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = Numrange{Valid: true}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *Numrange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Numrange{}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = Numrange{Valid: true}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src Numrange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src Numrange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Numrange) Scan(src interface{}) error {
if src == nil {
*dst = Numrange{}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Numrange) Value() (driver.Value, error) {
return EncodeValueText(src)
}

View File

@ -1,46 +0,0 @@
package pgtype_test
import (
"math/big"
"testing"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgtype/testutil"
)
func TestNumrangeTranscode(t *testing.T) {
testutil.TestSuccessfulTranscode(t, "numrange", []interface{}{
&pgtype.Numrange{
LowerType: pgtype.Empty,
UpperType: pgtype.Empty,
Valid: true,
},
&pgtype.Numrange{
Lower: pgtype.Numeric{Int: big.NewInt(-543), Exp: 3, Valid: true},
Upper: pgtype.Numeric{Int: big.NewInt(342), Exp: 1, Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
&pgtype.Numrange{
Lower: pgtype.Numeric{Int: big.NewInt(-42), Exp: 1, Valid: true},
Upper: pgtype.Numeric{Int: big.NewInt(-5), Exp: 0, Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
&pgtype.Numrange{
Lower: pgtype.Numeric{Int: big.NewInt(-42), Exp: 1, Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Unbounded,
Valid: true,
},
&pgtype.Numrange{
Upper: pgtype.Numeric{Int: big.NewInt(-42), Exp: 1, Valid: true},
LowerType: pgtype.Unbounded,
UpperType: pgtype.Exclusive,
Valid: true,
},
&pgtype.Numrange{},
})
}

View File

@ -320,15 +320,15 @@ func NewConnInfo() *ConnInfo {
ci.RegisterDataType(DataType{Value: &CIDR{}, Name: "cidr", OID: CIDROID})
ci.RegisterDataType(DataType{Value: &Circle{}, Name: "circle", OID: CircleOID})
ci.RegisterDataType(DataType{Value: &Date{}, Name: "date", OID: DateOID})
ci.RegisterDataType(DataType{Value: &Daterange{}, Name: "daterange", OID: DaterangeOID})
// ci.RegisterDataType(DataType{Value: &Daterange{}, Name: "daterange", OID: DaterangeOID})
ci.RegisterDataType(DataType{Value: &Float4{}, Name: "float4", OID: Float4OID})
ci.RegisterDataType(DataType{Value: &Float8{}, Name: "float8", OID: Float8OID})
ci.RegisterDataType(DataType{Value: &Inet{}, Name: "inet", OID: InetOID})
ci.RegisterDataType(DataType{Name: "int2", OID: Int2OID, Codec: Int2Codec{}})
ci.RegisterDataType(DataType{Value: &Int4{}, Name: "int4", OID: Int4OID})
ci.RegisterDataType(DataType{Value: &Int4range{}, Name: "int4range", OID: Int4rangeOID})
// ci.RegisterDataType(DataType{Value: &Int4range{}, Name: "int4range", OID: Int4rangeOID})
ci.RegisterDataType(DataType{Value: &Int8{}, Name: "int8", OID: Int8OID})
ci.RegisterDataType(DataType{Value: &Int8range{}, Name: "int8range", OID: Int8rangeOID})
// ci.RegisterDataType(DataType{Value: &Int8range{}, Name: "int8range", OID: Int8rangeOID})
ci.RegisterDataType(DataType{Value: &Interval{}, Name: "interval", OID: IntervalOID})
ci.RegisterDataType(DataType{Value: &JSON{}, Name: "json", OID: JSONOID})
ci.RegisterDataType(DataType{Value: &JSONB{}, Name: "jsonb", OID: JSONBOID})
@ -338,7 +338,7 @@ func NewConnInfo() *ConnInfo {
ci.RegisterDataType(DataType{Value: &Macaddr{}, Name: "macaddr", OID: MacaddrOID})
ci.RegisterDataType(DataType{Value: &Name{}, Name: "name", OID: NameOID})
ci.RegisterDataType(DataType{Value: &Numeric{}, Name: "numeric", OID: NumericOID})
ci.RegisterDataType(DataType{Value: &Numrange{}, Name: "numrange", OID: NumrangeOID})
// ci.RegisterDataType(DataType{Value: &Numrange{}, Name: "numrange", OID: NumrangeOID})
ci.RegisterDataType(DataType{Value: &OIDValue{}, Name: "oid", OID: OIDOID})
ci.RegisterDataType(DataType{Value: &Path{}, Name: "path", OID: PathOID})
ci.RegisterDataType(DataType{Value: &Point{}, Name: "point", OID: PointOID})
@ -349,10 +349,10 @@ func NewConnInfo() *ConnInfo {
ci.RegisterDataType(DataType{Value: &Time{}, Name: "time", OID: TimeOID})
ci.RegisterDataType(DataType{Value: &Timestamp{}, Name: "timestamp", OID: TimestampOID})
ci.RegisterDataType(DataType{Value: &Timestamptz{}, Name: "timestamptz", OID: TimestamptzOID})
ci.RegisterDataType(DataType{Value: &Tsrange{}, Name: "tsrange", OID: TsrangeOID})
ci.RegisterDataType(DataType{Value: &TsrangeArray{}, Name: "_tsrange", OID: TsrangeArrayOID})
ci.RegisterDataType(DataType{Value: &Tstzrange{}, Name: "tstzrange", OID: TstzrangeOID})
ci.RegisterDataType(DataType{Value: &TstzrangeArray{}, Name: "_tstzrange", OID: TstzrangeArrayOID})
// ci.RegisterDataType(DataType{Value: &Tsrange{}, Name: "tsrange", OID: TsrangeOID})
// ci.RegisterDataType(DataType{Value: &TsrangeArray{}, Name: "_tsrange", OID: TsrangeArrayOID})
// ci.RegisterDataType(DataType{Value: &Tstzrange{}, Name: "tstzrange", OID: TstzrangeOID})
// ci.RegisterDataType(DataType{Value: &TstzrangeArray{}, Name: "_tstzrange", OID: TstzrangeArrayOID})
ci.RegisterDataType(DataType{Value: &Unknown{}, Name: "unknown", OID: UnknownOID})
ci.RegisterDataType(DataType{Value: &UUID{}, Name: "uuid", OID: UUIDOID})
ci.RegisterDataType(DataType{Value: &Varbit{}, Name: "varbit", OID: VarbitOID})

View File

@ -1,277 +0,0 @@
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: %v", 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: %v", err)
}
buf.UnreadRune()
if r == ',' {
utr.LowerType = Unbounded
} else {
utr.Lower, err = rangeParseValue(buf)
if err != nil {
return nil, fmt.Errorf("invalid lower value: %v", err)
}
}
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("missing range separator: %v", 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: %v", 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: %v", err)
}
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("missing upper bound: %v", 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
}

View File

@ -1,177 +0,0 @@
package pgtype
import (
"bytes"
"testing"
)
func TestParseUntypedTextRange(t *testing.T) {
tests := []struct {
src string
result UntypedTextRange
err error
}{
{
src: `[1,2)`,
result: UntypedTextRange{Lower: "1", Upper: "2", LowerType: Inclusive, UpperType: Exclusive},
err: nil,
},
{
src: `[1,2]`,
result: UntypedTextRange{Lower: "1", Upper: "2", LowerType: Inclusive, UpperType: Inclusive},
err: nil,
},
{
src: `(1,3)`,
result: UntypedTextRange{Lower: "1", Upper: "3", LowerType: Exclusive, UpperType: Exclusive},
err: nil,
},
{
src: ` [1,2) `,
result: UntypedTextRange{Lower: "1", Upper: "2", LowerType: Inclusive, UpperType: Exclusive},
err: nil,
},
{
src: `[ foo , bar )`,
result: UntypedTextRange{Lower: " foo ", Upper: " bar ", LowerType: Inclusive, UpperType: Exclusive},
err: nil,
},
{
src: `["foo","bar")`,
result: UntypedTextRange{Lower: "foo", Upper: "bar", LowerType: Inclusive, UpperType: Exclusive},
err: nil,
},
{
src: `["f""oo","b""ar")`,
result: UntypedTextRange{Lower: `f"oo`, Upper: `b"ar`, LowerType: Inclusive, UpperType: Exclusive},
err: nil,
},
{
src: `["f""oo","b""ar")`,
result: UntypedTextRange{Lower: `f"oo`, Upper: `b"ar`, LowerType: Inclusive, UpperType: Exclusive},
err: nil,
},
{
src: `["","bar")`,
result: UntypedTextRange{Lower: ``, Upper: `bar`, LowerType: Inclusive, UpperType: Exclusive},
err: nil,
},
{
src: `[f\"oo\,,b\\ar\))`,
result: UntypedTextRange{Lower: `f"oo,`, Upper: `b\ar)`, LowerType: Inclusive, UpperType: Exclusive},
err: nil,
},
{
src: `empty`,
result: UntypedTextRange{Lower: "", Upper: "", LowerType: Empty, UpperType: Empty},
err: nil,
},
}
for i, tt := range tests {
r, err := ParseUntypedTextRange(tt.src)
if err != tt.err {
t.Errorf("%d. `%v`: expected err %v, got %v", i, tt.src, tt.err, err)
continue
}
if r.LowerType != tt.result.LowerType {
t.Errorf("%d. `%v`: expected result lower type %v, got %v", i, tt.src, string(tt.result.LowerType), string(r.LowerType))
}
if r.UpperType != tt.result.UpperType {
t.Errorf("%d. `%v`: expected result upper type %v, got %v", i, tt.src, string(tt.result.UpperType), string(r.UpperType))
}
if r.Lower != tt.result.Lower {
t.Errorf("%d. `%v`: expected result lower %v, got %v", i, tt.src, tt.result.Lower, r.Lower)
}
if r.Upper != tt.result.Upper {
t.Errorf("%d. `%v`: expected result upper %v, got %v", i, tt.src, tt.result.Upper, r.Upper)
}
}
}
func TestParseUntypedBinaryRange(t *testing.T) {
tests := []struct {
src []byte
result UntypedBinaryRange
err error
}{
{
src: []byte{0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 2, 0, 5},
result: UntypedBinaryRange{Lower: []byte{0, 4}, Upper: []byte{0, 5}, LowerType: Exclusive, UpperType: Exclusive},
err: nil,
},
{
src: []byte{1},
result: UntypedBinaryRange{Lower: nil, Upper: nil, LowerType: Empty, UpperType: Empty},
err: nil,
},
{
src: []byte{2, 0, 0, 0, 2, 0, 4, 0, 0, 0, 2, 0, 5},
result: UntypedBinaryRange{Lower: []byte{0, 4}, Upper: []byte{0, 5}, LowerType: Inclusive, UpperType: Exclusive},
err: nil,
},
{
src: []byte{4, 0, 0, 0, 2, 0, 4, 0, 0, 0, 2, 0, 5},
result: UntypedBinaryRange{Lower: []byte{0, 4}, Upper: []byte{0, 5}, LowerType: Exclusive, UpperType: Inclusive},
err: nil,
},
{
src: []byte{6, 0, 0, 0, 2, 0, 4, 0, 0, 0, 2, 0, 5},
result: UntypedBinaryRange{Lower: []byte{0, 4}, Upper: []byte{0, 5}, LowerType: Inclusive, UpperType: Inclusive},
err: nil,
},
{
src: []byte{8, 0, 0, 0, 2, 0, 5},
result: UntypedBinaryRange{Lower: nil, Upper: []byte{0, 5}, LowerType: Unbounded, UpperType: Exclusive},
err: nil,
},
{
src: []byte{12, 0, 0, 0, 2, 0, 5},
result: UntypedBinaryRange{Lower: nil, Upper: []byte{0, 5}, LowerType: Unbounded, UpperType: Inclusive},
err: nil,
},
{
src: []byte{16, 0, 0, 0, 2, 0, 4},
result: UntypedBinaryRange{Lower: []byte{0, 4}, Upper: nil, LowerType: Exclusive, UpperType: Unbounded},
err: nil,
},
{
src: []byte{18, 0, 0, 0, 2, 0, 4},
result: UntypedBinaryRange{Lower: []byte{0, 4}, Upper: nil, LowerType: Inclusive, UpperType: Unbounded},
err: nil,
},
{
src: []byte{24},
result: UntypedBinaryRange{Lower: nil, Upper: nil, LowerType: Unbounded, UpperType: Unbounded},
err: nil,
},
}
for i, tt := range tests {
r, err := ParseUntypedBinaryRange(tt.src)
if err != tt.err {
t.Errorf("%d. `%v`: expected err %v, got %v", i, tt.src, tt.err, err)
continue
}
if r.LowerType != tt.result.LowerType {
t.Errorf("%d. `%v`: expected result lower type %v, got %v", i, tt.src, string(tt.result.LowerType), string(r.LowerType))
}
if r.UpperType != tt.result.UpperType {
t.Errorf("%d. `%v`: expected result upper type %v, got %v", i, tt.src, string(tt.result.UpperType), string(r.UpperType))
}
if bytes.Compare(r.Lower, tt.result.Lower) != 0 {
t.Errorf("%d. `%v`: expected result lower %v, got %v", i, tt.src, tt.result.Lower, r.Lower)
}
if bytes.Compare(r.Upper, tt.result.Upper) != 0 {
t.Errorf("%d. `%v`: expected result upper %v, got %v", i, tt.src, tt.result.Upper, r.Upper)
}
}
}

View File

@ -1,257 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgio"
)
type Tsrange struct {
Lower Timestamp
Upper Timestamp
LowerType BoundType
UpperType BoundType
Valid bool
}
func (dst *Tsrange) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Tsrange{}
return nil
}
switch value := src.(type) {
case Tsrange:
*dst = value
case *Tsrange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to Tsrange", src)
}
return nil
}
func (src Tsrange) Get() interface{} {
if !src.Valid {
return nil
}
return src
}
func (src *Tsrange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Tsrange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Tsrange{}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = Tsrange{Valid: true}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *Tsrange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Tsrange{}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = Tsrange{Valid: true}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src Tsrange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src Tsrange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Tsrange) Scan(src interface{}) error {
if src == nil {
*dst = Tsrange{}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Tsrange) Value() (driver.Value, error) {
return EncodeValueText(src)
}

View File

@ -1,457 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type TsrangeArray struct {
Elements []Tsrange
Dimensions []ArrayDimension
Valid bool
}
func (dst *TsrangeArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = TsrangeArray{}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []Tsrange:
if value == nil {
*dst = TsrangeArray{}
} else if len(value) == 0 {
*dst = TsrangeArray{Valid: true}
} else {
*dst = TsrangeArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Valid: true,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = TsrangeArray{}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for TsrangeArray", src)
}
if elementsLength == 0 {
*dst = TsrangeArray{Valid: true}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to TsrangeArray", src)
}
*dst = TsrangeArray{
Elements: make([]Tsrange, elementsLength),
Dimensions: dimensions,
Valid: true,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Tsrange, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to TsrangeArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *TsrangeArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to TsrangeArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in TsrangeArray", err)
}
index++
return index, nil
}
func (dst TsrangeArray) Get() interface{} {
if !dst.Valid {
return nil
}
return dst
}
func (src *TsrangeArray) AssignTo(dst interface{}) error {
if !src.Valid {
return NullAssignTo(dst)
}
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]Tsrange:
*v = make([]Tsrange, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
}
func (src *TsrangeArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from TsrangeArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from TsrangeArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *TsrangeArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = TsrangeArray{}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Tsrange
if len(uta.Elements) > 0 {
elements = make([]Tsrange, len(uta.Elements))
for i, s := range uta.Elements {
var elem Tsrange
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = TsrangeArray{Elements: elements, Dimensions: uta.Dimensions, Valid: true}
return nil
}
func (dst *TsrangeArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = TsrangeArray{}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = TsrangeArray{Dimensions: arrayHeader.Dimensions, Valid: true}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Tsrange, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = TsrangeArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Valid: true}
return nil
}
func (src TsrangeArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src TsrangeArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("tsrange"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "tsrange")
}
for i := range src.Elements {
if !src.Elements[i].Valid {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *TsrangeArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src TsrangeArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}

View File

@ -1,41 +0,0 @@
package pgtype_test
import (
"testing"
"time"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgtype/testutil"
)
func TestTsrangeTranscode(t *testing.T) {
testutil.TestSuccessfulTranscodeEqFunc(t, "tsrange", []interface{}{
&pgtype.Tsrange{LowerType: pgtype.Empty, UpperType: pgtype.Empty, Valid: true},
&pgtype.Tsrange{
Lower: pgtype.Timestamp{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Timestamp{Time: time.Date(2028, 1, 1, 0, 23, 12, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
&pgtype.Tsrange{
Lower: pgtype.Timestamp{Time: time.Date(1800, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Timestamp{Time: time.Date(2200, 1, 1, 0, 23, 12, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
&pgtype.Tsrange{},
}, func(aa, bb interface{}) bool {
a := aa.(pgtype.Tsrange)
b := bb.(pgtype.Tsrange)
return a.Valid == b.Valid &&
a.Lower.Time.Equal(b.Lower.Time) &&
a.Lower.Valid == b.Lower.Valid &&
a.Lower.InfinityModifier == b.Lower.InfinityModifier &&
a.Upper.Time.Equal(b.Upper.Time) &&
a.Upper.Valid == b.Upper.Valid &&
a.Upper.InfinityModifier == b.Upper.InfinityModifier
})
}

View File

@ -1,257 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgio"
)
type Tstzrange struct {
Lower Timestamptz
Upper Timestamptz
LowerType BoundType
UpperType BoundType
Valid bool
}
func (dst *Tstzrange) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Tstzrange{}
return nil
}
switch value := src.(type) {
case Tstzrange:
*dst = value
case *Tstzrange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to Tstzrange", src)
}
return nil
}
func (src Tstzrange) Get() interface{} {
if !src.Valid {
return nil
}
return src
}
func (src *Tstzrange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Tstzrange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Tstzrange{}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = Tstzrange{Valid: true}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *Tstzrange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Tstzrange{}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = Tstzrange{Valid: true}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src Tstzrange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src Tstzrange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Tstzrange) Scan(src interface{}) error {
if src == nil {
*dst = Tstzrange{}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Tstzrange) Value() (driver.Value, error) {
return EncodeValueText(src)
}

View File

@ -1,457 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type TstzrangeArray struct {
Elements []Tstzrange
Dimensions []ArrayDimension
Valid bool
}
func (dst *TstzrangeArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = TstzrangeArray{}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []Tstzrange:
if value == nil {
*dst = TstzrangeArray{}
} else if len(value) == 0 {
*dst = TstzrangeArray{Valid: true}
} else {
*dst = TstzrangeArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Valid: true,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = TstzrangeArray{}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for TstzrangeArray", src)
}
if elementsLength == 0 {
*dst = TstzrangeArray{Valid: true}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to TstzrangeArray", src)
}
*dst = TstzrangeArray{
Elements: make([]Tstzrange, elementsLength),
Dimensions: dimensions,
Valid: true,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Tstzrange, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to TstzrangeArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *TstzrangeArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to TstzrangeArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in TstzrangeArray", err)
}
index++
return index, nil
}
func (dst TstzrangeArray) Get() interface{} {
if !dst.Valid {
return nil
}
return dst
}
func (src *TstzrangeArray) AssignTo(dst interface{}) error {
if !src.Valid {
return NullAssignTo(dst)
}
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]Tstzrange:
*v = make([]Tstzrange, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
}
func (src *TstzrangeArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from TstzrangeArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from TstzrangeArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *TstzrangeArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = TstzrangeArray{}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Tstzrange
if len(uta.Elements) > 0 {
elements = make([]Tstzrange, len(uta.Elements))
for i, s := range uta.Elements {
var elem Tstzrange
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = TstzrangeArray{Elements: elements, Dimensions: uta.Dimensions, Valid: true}
return nil
}
func (dst *TstzrangeArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = TstzrangeArray{}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = TstzrangeArray{Dimensions: arrayHeader.Dimensions, Valid: true}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Tstzrange, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = TstzrangeArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Valid: true}
return nil
}
func (src TstzrangeArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src TstzrangeArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("tstzrange"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "tstzrange")
}
for i := range src.Elements {
if !src.Elements[i].Valid {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *TstzrangeArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src TstzrangeArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}

View File

@ -1,49 +0,0 @@
package pgtype_test
import (
"testing"
"time"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgtype/testutil"
"github.com/stretchr/testify/require"
)
func TestTstzrangeTranscode(t *testing.T) {
testutil.TestSuccessfulTranscodeEqFunc(t, "tstzrange", []interface{}{
&pgtype.Tstzrange{LowerType: pgtype.Empty, UpperType: pgtype.Empty, Valid: true},
&pgtype.Tstzrange{
Lower: pgtype.Timestamptz{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Timestamptz{Time: time.Date(2028, 1, 1, 0, 23, 12, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
&pgtype.Tstzrange{
Lower: pgtype.Timestamptz{Time: time.Date(1800, 12, 31, 0, 0, 0, 0, time.UTC), Valid: true},
Upper: pgtype.Timestamptz{Time: time.Date(2200, 1, 1, 0, 23, 12, 0, time.UTC), Valid: true},
LowerType: pgtype.Inclusive,
UpperType: pgtype.Exclusive,
Valid: true,
},
&pgtype.Tstzrange{},
}, func(aa, bb interface{}) bool {
a := aa.(pgtype.Tstzrange)
b := bb.(pgtype.Tstzrange)
return a.Valid == b.Valid &&
a.Lower.Time.Equal(b.Lower.Time) &&
a.Lower.Valid == b.Lower.Valid &&
a.Lower.InfinityModifier == b.Lower.InfinityModifier &&
a.Upper.Time.Equal(b.Upper.Time) &&
a.Upper.Valid == b.Upper.Valid &&
a.Upper.InfinityModifier == b.Upper.InfinityModifier
})
}
// https://github.com/jackc/pgtype/issues/74
func TestTstzRangeDecodeTextInvalid(t *testing.T) {
tstzrange := &pgtype.Tstzrange{}
err := tstzrange.DecodeText(nil, []byte(`[eeee,)`))
require.Error(t, err)
}

View File

@ -1,259 +0,0 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"fmt"
"io"
"github.com/jackc/pgio"
)
type <%= range_type %> struct {
Lower <%= element_type %>
Upper <%= element_type %>
LowerType BoundType
UpperType BoundType
Valid bool
}
func (dst *<%= range_type %>) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = <%= range_type %>{}
return nil
}
switch value := src.(type) {
case <%= range_type %>:
*dst = value
case *<%= range_type %>:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to <%= range_type %>", src)
}
return nil
}
func (src <%= range_type %>) Get() interface{} {
if !src.Valid {
return nil
}
return src
}
func (src *<%= range_type %>) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *<%= range_type %>) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = <%= range_type %>{}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = <%= range_type %>{Valid: true}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *<%= range_type %>) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = <%= range_type %>{}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = <%= range_type %>{Valid: true}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src <%= range_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src <%= range_type %>) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
if !src.Valid {
return nil, nil
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *<%= range_type %>) Scan(src interface{}) error {
if src == nil {
*dst = <%= range_type %>{}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src <%= range_type %>) Value() (driver.Value, error) {
return EncodeValueText(src)
}

View File

@ -1,7 +0,0 @@
erb range_type=Int4range element_type=Int4 typed_range.go.erb > int4range.go
erb range_type=Int8range element_type=Int8 typed_range.go.erb > int8range.go
erb range_type=Tsrange element_type=Timestamp typed_range.go.erb > tsrange.go
erb range_type=Tstzrange element_type=Timestamptz typed_range.go.erb > tstzrange.go
erb range_type=Daterange element_type=Date typed_range.go.erb > daterange.go
erb range_type=Numrange element_type=Numeric typed_range.go.erb > numrange.go
goimports -w *range.go