mirror of https://github.com/jackc/pgx.git
Temporarily remove range type support
parent
d2cf33ed40
commit
ffa1fdd66e
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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{},
|
||||
})
|
||||
}
|
|
@ -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})
|
||||
|
|
277
pgtype/range.go
277
pgtype/range.go
|
@ -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
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
})
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue