Build / rewrite / port multirange support
This commit is contained in:
@@ -0,0 +1,443 @@
|
||||
package pgtype
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/jackc/pgx/v5/internal/pgio"
|
||||
)
|
||||
|
||||
// MultirangeGetter is a type that can be converted into a PostgreSQL multirange.
|
||||
type MultirangeGetter interface {
|
||||
// IsNull returns true if the value is SQL NULL.
|
||||
IsNull() bool
|
||||
|
||||
// Len returns the number of elements in the multirange.
|
||||
Len() int
|
||||
|
||||
// Index returns the element at i.
|
||||
Index(i int) any
|
||||
|
||||
// IndexType returns a non-nil scan target of the type Index will return. This is used by MultirangeCodec.PlanEncode.
|
||||
IndexType() any
|
||||
}
|
||||
|
||||
// MultirangeSetter is a type can be set from a PostgreSQL multirange.
|
||||
type MultirangeSetter interface {
|
||||
// ScanNull sets the value to SQL NULL.
|
||||
ScanNull() error
|
||||
|
||||
// SetLen prepares the value such that ScanIndex can be called for each element. This will remove any existing
|
||||
// elements.
|
||||
SetLen(n int) error
|
||||
|
||||
// ScanIndex returns a value usable as a scan target for i. SetLen must be called before ScanIndex.
|
||||
ScanIndex(i int) any
|
||||
|
||||
// ScanIndexType returns a non-nil scan target of the type ScanIndex will return. This is used by
|
||||
// MultirangeCodec.PlanScan.
|
||||
ScanIndexType() any
|
||||
}
|
||||
|
||||
// MultirangeCodec is a codec for any multirange type.
|
||||
type MultirangeCodec struct {
|
||||
ElementType *Type
|
||||
}
|
||||
|
||||
func (c *MultirangeCodec) FormatSupported(format int16) bool {
|
||||
return c.ElementType.Codec.FormatSupported(format)
|
||||
}
|
||||
|
||||
func (c *MultirangeCodec) PreferredFormat() int16 {
|
||||
return c.ElementType.Codec.PreferredFormat()
|
||||
}
|
||||
|
||||
func (c *MultirangeCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
|
||||
multirangeValuer, ok := value.(MultirangeGetter)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
elementType := multirangeValuer.IndexType()
|
||||
|
||||
elementEncodePlan := m.PlanEncode(c.ElementType.OID, format, elementType)
|
||||
if elementEncodePlan == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch format {
|
||||
case BinaryFormatCode:
|
||||
return &encodePlanMultirangeCodecBinary{ac: c, m: m, oid: oid}
|
||||
case TextFormatCode:
|
||||
return &encodePlanMultirangeCodecText{ac: c, m: m, oid: oid}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type encodePlanMultirangeCodecText struct {
|
||||
ac *MultirangeCodec
|
||||
m *Map
|
||||
oid uint32
|
||||
}
|
||||
|
||||
func (p *encodePlanMultirangeCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
|
||||
multirange := value.(MultirangeGetter)
|
||||
|
||||
if multirange.IsNull() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
elementCount := multirange.Len()
|
||||
|
||||
buf = append(buf, '{')
|
||||
|
||||
var encodePlan EncodePlan
|
||||
var lastElemType reflect.Type
|
||||
inElemBuf := make([]byte, 0, 32)
|
||||
for i := 0; i < elementCount; i++ {
|
||||
if i > 0 {
|
||||
buf = append(buf, ',')
|
||||
}
|
||||
|
||||
elem := multirange.Index(i)
|
||||
var elemBuf []byte
|
||||
if elem != nil {
|
||||
elemType := reflect.TypeOf(elem)
|
||||
if lastElemType != elemType {
|
||||
lastElemType = elemType
|
||||
encodePlan = p.m.PlanEncode(p.ac.ElementType.OID, TextFormatCode, elem)
|
||||
if encodePlan == nil {
|
||||
return nil, fmt.Errorf("unable to encode %v", multirange.Index(i))
|
||||
}
|
||||
}
|
||||
elemBuf, err = encodePlan.Encode(elem, inElemBuf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if elemBuf == nil {
|
||||
return nil, fmt.Errorf("multirange cannot contain NULL element")
|
||||
} else {
|
||||
buf = append(buf, elemBuf...)
|
||||
}
|
||||
}
|
||||
|
||||
buf = append(buf, '}')
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
type encodePlanMultirangeCodecBinary struct {
|
||||
ac *MultirangeCodec
|
||||
m *Map
|
||||
oid uint32
|
||||
}
|
||||
|
||||
func (p *encodePlanMultirangeCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
|
||||
multirange := value.(MultirangeGetter)
|
||||
|
||||
if multirange.IsNull() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
elementCount := multirange.Len()
|
||||
|
||||
buf = pgio.AppendInt32(buf, int32(elementCount))
|
||||
|
||||
var encodePlan EncodePlan
|
||||
var lastElemType reflect.Type
|
||||
for i := 0; i < elementCount; i++ {
|
||||
sp := len(buf)
|
||||
buf = pgio.AppendInt32(buf, -1)
|
||||
|
||||
elem := multirange.Index(i)
|
||||
var elemBuf []byte
|
||||
if elem != nil {
|
||||
elemType := reflect.TypeOf(elem)
|
||||
if lastElemType != elemType {
|
||||
lastElemType = elemType
|
||||
encodePlan = p.m.PlanEncode(p.ac.ElementType.OID, BinaryFormatCode, elem)
|
||||
if encodePlan == nil {
|
||||
return nil, fmt.Errorf("unable to encode %v", multirange.Index(i))
|
||||
}
|
||||
}
|
||||
elemBuf, err = encodePlan.Encode(elem, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if elemBuf == nil {
|
||||
return nil, fmt.Errorf("multirange cannot contain NULL element")
|
||||
} else {
|
||||
buf = elemBuf
|
||||
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
|
||||
}
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (c *MultirangeCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
|
||||
multirangeScanner, ok := target.(MultirangeSetter)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
elementType := multirangeScanner.ScanIndexType()
|
||||
|
||||
elementScanPlan := m.PlanScan(c.ElementType.OID, format, elementType)
|
||||
if _, ok := elementScanPlan.(*scanPlanFail); ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &scanPlanMultirangeCodec{
|
||||
multirangeCodec: c,
|
||||
m: m,
|
||||
oid: oid,
|
||||
formatCode: format,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *MultirangeCodec) decodeBinary(m *Map, multirangeOID uint32, src []byte, multirange MultirangeSetter) error {
|
||||
rp := 0
|
||||
|
||||
elementCount := int(binary.BigEndian.Uint32(src[rp:]))
|
||||
rp += 4
|
||||
|
||||
err := multirange.SetLen(elementCount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if elementCount == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
elementScanPlan := c.ElementType.Codec.PlanScan(m, c.ElementType.OID, BinaryFormatCode, multirange.ScanIndex(0))
|
||||
if elementScanPlan == nil {
|
||||
elementScanPlan = m.PlanScan(c.ElementType.OID, BinaryFormatCode, multirange.ScanIndex(0))
|
||||
}
|
||||
|
||||
for i := 0; i < elementCount; i++ {
|
||||
elem := multirange.ScanIndex(i)
|
||||
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
|
||||
rp += 4
|
||||
var elemSrc []byte
|
||||
if elemLen >= 0 {
|
||||
elemSrc = src[rp : rp+elemLen]
|
||||
rp += elemLen
|
||||
}
|
||||
err = elementScanPlan.Scan(elemSrc, elem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to scan multirange element %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *MultirangeCodec) decodeText(m *Map, multirangeOID uint32, src []byte, multirange MultirangeSetter) error {
|
||||
elements, err := parseUntypedTextMultirange(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = multirange.SetLen(len(elements))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(elements) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
elementScanPlan := c.ElementType.Codec.PlanScan(m, c.ElementType.OID, TextFormatCode, multirange.ScanIndex(0))
|
||||
if elementScanPlan == nil {
|
||||
elementScanPlan = m.PlanScan(c.ElementType.OID, TextFormatCode, multirange.ScanIndex(0))
|
||||
}
|
||||
|
||||
for i, s := range elements {
|
||||
elem := multirange.ScanIndex(i)
|
||||
err = elementScanPlan.Scan([]byte(s), elem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type scanPlanMultirangeCodec struct {
|
||||
multirangeCodec *MultirangeCodec
|
||||
m *Map
|
||||
oid uint32
|
||||
formatCode int16
|
||||
elementScanPlan ScanPlan
|
||||
}
|
||||
|
||||
func (spac *scanPlanMultirangeCodec) Scan(src []byte, dst any) error {
|
||||
c := spac.multirangeCodec
|
||||
m := spac.m
|
||||
oid := spac.oid
|
||||
formatCode := spac.formatCode
|
||||
|
||||
multirange := dst.(MultirangeSetter)
|
||||
|
||||
if src == nil {
|
||||
return multirange.ScanNull()
|
||||
}
|
||||
|
||||
switch formatCode {
|
||||
case BinaryFormatCode:
|
||||
return c.decodeBinary(m, oid, src, multirange)
|
||||
case TextFormatCode:
|
||||
return c.decodeText(m, oid, src, multirange)
|
||||
default:
|
||||
return fmt.Errorf("unknown format code %d", formatCode)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *MultirangeCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
|
||||
if src == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
switch format {
|
||||
case TextFormatCode:
|
||||
return string(src), nil
|
||||
case BinaryFormatCode:
|
||||
buf := make([]byte, len(src))
|
||||
copy(buf, src)
|
||||
return buf, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown format code %d", format)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *MultirangeCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
|
||||
if src == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var multirange Multirange[Range[any]]
|
||||
err := m.PlanScan(oid, format, &multirange).Scan(src, &multirange)
|
||||
return multirange, err
|
||||
}
|
||||
|
||||
func parseUntypedTextMultirange(src []byte) ([]string, error) {
|
||||
elements := make([]string, 0)
|
||||
|
||||
buf := bytes.NewBuffer(src)
|
||||
|
||||
skipWhitespace(buf)
|
||||
|
||||
r, _, err := buf.ReadRune()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid array: %v", err)
|
||||
}
|
||||
|
||||
if r != '{' {
|
||||
return nil, fmt.Errorf("invalid multirange, expected '{': %v", err)
|
||||
}
|
||||
|
||||
parseValueLoop:
|
||||
for {
|
||||
r, _, err = buf.ReadRune()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid multirange: %v", err)
|
||||
}
|
||||
|
||||
switch r {
|
||||
case ',': // skip range separator
|
||||
case '}':
|
||||
break parseValueLoop
|
||||
default:
|
||||
buf.UnreadRune()
|
||||
value, err := parseRange(buf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid multirange value: %v", err)
|
||||
}
|
||||
elements = append(elements, value)
|
||||
}
|
||||
}
|
||||
|
||||
skipWhitespace(buf)
|
||||
|
||||
if buf.Len() > 0 {
|
||||
return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
|
||||
}
|
||||
|
||||
return elements, nil
|
||||
|
||||
}
|
||||
|
||||
func parseRange(buf *bytes.Buffer) (string, error) {
|
||||
s := &bytes.Buffer{}
|
||||
|
||||
boundSepRead := false
|
||||
for {
|
||||
r, _, err := buf.ReadRune()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
switch r {
|
||||
case ',', '}':
|
||||
if r == ',' && !boundSepRead {
|
||||
boundSepRead = true
|
||||
break
|
||||
}
|
||||
buf.UnreadRune()
|
||||
return s.String(), nil
|
||||
}
|
||||
|
||||
s.WriteRune(r)
|
||||
}
|
||||
}
|
||||
|
||||
// Multirange is a generic multirange type.
|
||||
//
|
||||
// T should implement RangeValuer and *T should implement RangeScanner. However, there does not appear to be a way to
|
||||
// enforce the RangeScanner constraint.
|
||||
type Multirange[T RangeValuer] []T
|
||||
|
||||
func (r Multirange[T]) IsNull() bool {
|
||||
return r == nil
|
||||
}
|
||||
|
||||
func (r Multirange[T]) Len() int {
|
||||
return len(r)
|
||||
}
|
||||
|
||||
func (r Multirange[T]) Index(i int) any {
|
||||
return r[i]
|
||||
}
|
||||
|
||||
func (r Multirange[T]) IndexType() any {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
func (r *Multirange[T]) ScanNull() error {
|
||||
*r = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Multirange[T]) SetLen(n int) error {
|
||||
*r = make([]T, n)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r Multirange[T]) ScanIndex(i int) any {
|
||||
return &r[i]
|
||||
}
|
||||
|
||||
func (r Multirange[T]) ScanIndexType() any {
|
||||
return new(T)
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package pgtype_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
pgx "github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/jackc/pgx/v5/pgxtest"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMultirangeCodecTranscode(t *testing.T) {
|
||||
skipCockroachDB(t, "Server does not support range types (see https://github.com/cockroachdb/cockroach/issues/27791)")
|
||||
|
||||
pgxtest.RunValueRoundTripTests(context.Background(), t, defaultConnTestRunner, nil, "int4multirange", []pgxtest.ValueRoundTripTest{
|
||||
{
|
||||
pgtype.Multirange[pgtype.Range[pgtype.Int4]](nil),
|
||||
new(pgtype.Multirange[pgtype.Range[pgtype.Int4]]),
|
||||
func(a any) bool { return reflect.DeepEqual(pgtype.Multirange[pgtype.Range[pgtype.Int4]](nil), a) },
|
||||
},
|
||||
{
|
||||
pgtype.Multirange[pgtype.Range[pgtype.Int4]]{},
|
||||
new(pgtype.Multirange[pgtype.Range[pgtype.Int4]]),
|
||||
func(a any) bool { return reflect.DeepEqual(pgtype.Multirange[pgtype.Range[pgtype.Int4]]{}, a) },
|
||||
},
|
||||
{
|
||||
pgtype.Multirange[pgtype.Range[pgtype.Int4]]{
|
||||
{
|
||||
Lower: pgtype.Int4{Int32: 1, Valid: true},
|
||||
Upper: pgtype.Int4{Int32: 5, Valid: true},
|
||||
LowerType: pgtype.Inclusive,
|
||||
UpperType: pgtype.Exclusive,
|
||||
Valid: true,
|
||||
},
|
||||
{
|
||||
Lower: pgtype.Int4{Int32: 7, Valid: true},
|
||||
Upper: pgtype.Int4{Int32: 9, Valid: true},
|
||||
LowerType: pgtype.Inclusive,
|
||||
UpperType: pgtype.Exclusive,
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
new(pgtype.Multirange[pgtype.Range[pgtype.Int4]]),
|
||||
func(a any) bool {
|
||||
return reflect.DeepEqual(pgtype.Multirange[pgtype.Range[pgtype.Int4]]{
|
||||
{
|
||||
Lower: pgtype.Int4{Int32: 1, Valid: true},
|
||||
Upper: pgtype.Int4{Int32: 5, Valid: true},
|
||||
LowerType: pgtype.Inclusive,
|
||||
UpperType: pgtype.Exclusive,
|
||||
Valid: true,
|
||||
},
|
||||
{
|
||||
Lower: pgtype.Int4{Int32: 7, Valid: true},
|
||||
Upper: pgtype.Int4{Int32: 9, Valid: true},
|
||||
LowerType: pgtype.Inclusive,
|
||||
UpperType: pgtype.Exclusive,
|
||||
Valid: true,
|
||||
},
|
||||
}, a)
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestMultirangeCodecDecodeValue(t *testing.T) {
|
||||
skipCockroachDB(t, "Server does not support range types (see https://github.com/cockroachdb/cockroach/issues/27791)")
|
||||
|
||||
defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, _ testing.TB, conn *pgx.Conn) {
|
||||
|
||||
for _, tt := range []struct {
|
||||
sql string
|
||||
expected any
|
||||
}{
|
||||
{
|
||||
sql: `select int4multirange(int4range(1, 5), int4range(7,9))`,
|
||||
expected: pgtype.Multirange[pgtype.Range[any]]{
|
||||
{
|
||||
Lower: int32(1),
|
||||
Upper: int32(5),
|
||||
LowerType: pgtype.Inclusive,
|
||||
UpperType: pgtype.Exclusive,
|
||||
Valid: true,
|
||||
},
|
||||
{
|
||||
Lower: int32(7),
|
||||
Upper: int32(9),
|
||||
LowerType: pgtype.Inclusive,
|
||||
UpperType: pgtype.Exclusive,
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tt.sql, func(t *testing.T) {
|
||||
rows, err := conn.Query(ctx, tt.sql)
|
||||
require.NoError(t, err)
|
||||
|
||||
for rows.Next() {
|
||||
values, err := rows.Values()
|
||||
require.NoError(t, err)
|
||||
require.Len(t, values, 1)
|
||||
require.Equal(t, tt.expected, values[0])
|
||||
}
|
||||
|
||||
require.NoError(t, rows.Err())
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
+122
-92
@@ -12,97 +12,109 @@ import (
|
||||
|
||||
// PostgreSQL oids for common types
|
||||
const (
|
||||
BoolOID = 16
|
||||
ByteaOID = 17
|
||||
QCharOID = 18
|
||||
NameOID = 19
|
||||
Int8OID = 20
|
||||
Int2OID = 21
|
||||
Int4OID = 23
|
||||
TextOID = 25
|
||||
OIDOID = 26
|
||||
TIDOID = 27
|
||||
XIDOID = 28
|
||||
CIDOID = 29
|
||||
JSONOID = 114
|
||||
JSONArrayOID = 199
|
||||
PointOID = 600
|
||||
LsegOID = 601
|
||||
PathOID = 602
|
||||
BoxOID = 603
|
||||
PolygonOID = 604
|
||||
LineOID = 628
|
||||
LineArrayOID = 629
|
||||
CIDROID = 650
|
||||
CIDRArrayOID = 651
|
||||
Float4OID = 700
|
||||
Float8OID = 701
|
||||
CircleOID = 718
|
||||
CircleArrayOID = 719
|
||||
UnknownOID = 705
|
||||
MacaddrOID = 829
|
||||
InetOID = 869
|
||||
BoolArrayOID = 1000
|
||||
QCharArrayOID = 1003
|
||||
NameArrayOID = 1003
|
||||
Int2ArrayOID = 1005
|
||||
Int4ArrayOID = 1007
|
||||
TextArrayOID = 1009
|
||||
TIDArrayOID = 1010
|
||||
ByteaArrayOID = 1001
|
||||
XIDArrayOID = 1011
|
||||
CIDArrayOID = 1012
|
||||
BPCharArrayOID = 1014
|
||||
VarcharArrayOID = 1015
|
||||
Int8ArrayOID = 1016
|
||||
PointArrayOID = 1017
|
||||
LsegArrayOID = 1018
|
||||
PathArrayOID = 1019
|
||||
BoxArrayOID = 1020
|
||||
Float4ArrayOID = 1021
|
||||
Float8ArrayOID = 1022
|
||||
PolygonArrayOID = 1027
|
||||
OIDArrayOID = 1028
|
||||
ACLItemOID = 1033
|
||||
ACLItemArrayOID = 1034
|
||||
MacaddrArrayOID = 1040
|
||||
InetArrayOID = 1041
|
||||
BPCharOID = 1042
|
||||
VarcharOID = 1043
|
||||
DateOID = 1082
|
||||
TimeOID = 1083
|
||||
TimestampOID = 1114
|
||||
TimestampArrayOID = 1115
|
||||
DateArrayOID = 1182
|
||||
TimeArrayOID = 1183
|
||||
TimestamptzOID = 1184
|
||||
TimestamptzArrayOID = 1185
|
||||
IntervalOID = 1186
|
||||
IntervalArrayOID = 1187
|
||||
NumericArrayOID = 1231
|
||||
BitOID = 1560
|
||||
BitArrayOID = 1561
|
||||
VarbitOID = 1562
|
||||
VarbitArrayOID = 1563
|
||||
NumericOID = 1700
|
||||
RecordOID = 2249
|
||||
RecordArrayOID = 2287
|
||||
UUIDOID = 2950
|
||||
UUIDArrayOID = 2951
|
||||
JSONBOID = 3802
|
||||
JSONBArrayOID = 3807
|
||||
DaterangeOID = 3912
|
||||
DaterangeArrayOID = 3913
|
||||
Int4rangeOID = 3904
|
||||
Int4rangeArrayOID = 3905
|
||||
NumrangeOID = 3906
|
||||
NumrangeArrayOID = 3907
|
||||
TsrangeOID = 3908
|
||||
TsrangeArrayOID = 3909
|
||||
TstzrangeOID = 3910
|
||||
TstzrangeArrayOID = 3911
|
||||
Int8rangeOID = 3926
|
||||
Int8rangeArrayOID = 3927
|
||||
BoolOID = 16
|
||||
ByteaOID = 17
|
||||
QCharOID = 18
|
||||
NameOID = 19
|
||||
Int8OID = 20
|
||||
Int2OID = 21
|
||||
Int4OID = 23
|
||||
TextOID = 25
|
||||
OIDOID = 26
|
||||
TIDOID = 27
|
||||
XIDOID = 28
|
||||
CIDOID = 29
|
||||
JSONOID = 114
|
||||
JSONArrayOID = 199
|
||||
PointOID = 600
|
||||
LsegOID = 601
|
||||
PathOID = 602
|
||||
BoxOID = 603
|
||||
PolygonOID = 604
|
||||
LineOID = 628
|
||||
LineArrayOID = 629
|
||||
CIDROID = 650
|
||||
CIDRArrayOID = 651
|
||||
Float4OID = 700
|
||||
Float8OID = 701
|
||||
CircleOID = 718
|
||||
CircleArrayOID = 719
|
||||
UnknownOID = 705
|
||||
MacaddrOID = 829
|
||||
InetOID = 869
|
||||
BoolArrayOID = 1000
|
||||
QCharArrayOID = 1003
|
||||
NameArrayOID = 1003
|
||||
Int2ArrayOID = 1005
|
||||
Int4ArrayOID = 1007
|
||||
TextArrayOID = 1009
|
||||
TIDArrayOID = 1010
|
||||
ByteaArrayOID = 1001
|
||||
XIDArrayOID = 1011
|
||||
CIDArrayOID = 1012
|
||||
BPCharArrayOID = 1014
|
||||
VarcharArrayOID = 1015
|
||||
Int8ArrayOID = 1016
|
||||
PointArrayOID = 1017
|
||||
LsegArrayOID = 1018
|
||||
PathArrayOID = 1019
|
||||
BoxArrayOID = 1020
|
||||
Float4ArrayOID = 1021
|
||||
Float8ArrayOID = 1022
|
||||
PolygonArrayOID = 1027
|
||||
OIDArrayOID = 1028
|
||||
ACLItemOID = 1033
|
||||
ACLItemArrayOID = 1034
|
||||
MacaddrArrayOID = 1040
|
||||
InetArrayOID = 1041
|
||||
BPCharOID = 1042
|
||||
VarcharOID = 1043
|
||||
DateOID = 1082
|
||||
TimeOID = 1083
|
||||
TimestampOID = 1114
|
||||
TimestampArrayOID = 1115
|
||||
DateArrayOID = 1182
|
||||
TimeArrayOID = 1183
|
||||
TimestamptzOID = 1184
|
||||
TimestamptzArrayOID = 1185
|
||||
IntervalOID = 1186
|
||||
IntervalArrayOID = 1187
|
||||
NumericArrayOID = 1231
|
||||
BitOID = 1560
|
||||
BitArrayOID = 1561
|
||||
VarbitOID = 1562
|
||||
VarbitArrayOID = 1563
|
||||
NumericOID = 1700
|
||||
RecordOID = 2249
|
||||
RecordArrayOID = 2287
|
||||
UUIDOID = 2950
|
||||
UUIDArrayOID = 2951
|
||||
JSONBOID = 3802
|
||||
JSONBArrayOID = 3807
|
||||
DaterangeOID = 3912
|
||||
DaterangeArrayOID = 3913
|
||||
Int4rangeOID = 3904
|
||||
Int4rangeArrayOID = 3905
|
||||
NumrangeOID = 3906
|
||||
NumrangeArrayOID = 3907
|
||||
TsrangeOID = 3908
|
||||
TsrangeArrayOID = 3909
|
||||
TstzrangeOID = 3910
|
||||
TstzrangeArrayOID = 3911
|
||||
Int8rangeOID = 3926
|
||||
Int8rangeArrayOID = 3927
|
||||
Int4multirangeOID = 4451
|
||||
NummultirangeOID = 4532
|
||||
TsmultirangeOID = 4533
|
||||
TstzmultirangeOID = 4534
|
||||
DatemultirangeOID = 4535
|
||||
Int8multirangeOID = 4536
|
||||
Int4multirangeArrayOID = 6150
|
||||
NummultirangeArrayOID = 6151
|
||||
TsmultirangeArrayOID = 6152
|
||||
TstzmultirangeArrayOID = 6153
|
||||
DatemultirangeArrayOID = 6155
|
||||
Int8multirangeArrayOID = 6157
|
||||
)
|
||||
|
||||
type InfinityModifier int8
|
||||
@@ -222,6 +234,7 @@ func NewMap() *Map {
|
||||
},
|
||||
}
|
||||
|
||||
// Base types
|
||||
m.RegisterType(&Type{Name: "aclitem", OID: ACLItemOID, Codec: &TextFormatOnlyCodec{TextCodec{}}})
|
||||
m.RegisterType(&Type{Name: "bit", OID: BitOID, Codec: BitsCodec{}})
|
||||
m.RegisterType(&Type{Name: "bool", OID: BoolOID, Codec: BoolCodec{}})
|
||||
@@ -263,6 +276,7 @@ func NewMap() *Map {
|
||||
m.RegisterType(&Type{Name: "varchar", OID: VarcharOID, Codec: TextCodec{}})
|
||||
m.RegisterType(&Type{Name: "xid", OID: XIDOID, Codec: Uint32Codec{}})
|
||||
|
||||
// Range types
|
||||
m.RegisterType(&Type{Name: "daterange", OID: DaterangeOID, Codec: &RangeCodec{ElementType: m.oidToType[DateOID]}})
|
||||
m.RegisterType(&Type{Name: "int4range", OID: Int4rangeOID, Codec: &RangeCodec{ElementType: m.oidToType[Int4OID]}})
|
||||
m.RegisterType(&Type{Name: "int8range", OID: Int8rangeOID, Codec: &RangeCodec{ElementType: m.oidToType[Int8OID]}})
|
||||
@@ -270,6 +284,15 @@ func NewMap() *Map {
|
||||
m.RegisterType(&Type{Name: "tsrange", OID: TsrangeOID, Codec: &RangeCodec{ElementType: m.oidToType[TimestampOID]}})
|
||||
m.RegisterType(&Type{Name: "tstzrange", OID: TstzrangeOID, Codec: &RangeCodec{ElementType: m.oidToType[TimestamptzOID]}})
|
||||
|
||||
// Multirange types
|
||||
m.RegisterType(&Type{Name: "datemultirange", OID: DatemultirangeOID, Codec: &MultirangeCodec{ElementType: m.oidToType[DaterangeOID]}})
|
||||
m.RegisterType(&Type{Name: "int4multirange", OID: Int4multirangeOID, Codec: &MultirangeCodec{ElementType: m.oidToType[Int4rangeOID]}})
|
||||
m.RegisterType(&Type{Name: "int8multirange", OID: Int8multirangeOID, Codec: &MultirangeCodec{ElementType: m.oidToType[Int8rangeOID]}})
|
||||
m.RegisterType(&Type{Name: "nummultirange", OID: NummultirangeOID, Codec: &MultirangeCodec{ElementType: m.oidToType[NumrangeOID]}})
|
||||
m.RegisterType(&Type{Name: "tsmultirange", OID: TsmultirangeOID, Codec: &MultirangeCodec{ElementType: m.oidToType[TsrangeOID]}})
|
||||
m.RegisterType(&Type{Name: "tstzmultirange", OID: TstzmultirangeOID, Codec: &MultirangeCodec{ElementType: m.oidToType[TstzrangeOID]}})
|
||||
|
||||
// Array types
|
||||
m.RegisterType(&Type{Name: "_aclitem", OID: ACLItemArrayOID, Codec: &ArrayCodec{ElementType: m.oidToType[ACLItemOID]}})
|
||||
m.RegisterType(&Type{Name: "_bit", OID: BitArrayOID, Codec: &ArrayCodec{ElementType: m.oidToType[BitOID]}})
|
||||
m.RegisterType(&Type{Name: "_bool", OID: BoolArrayOID, Codec: &ArrayCodec{ElementType: m.oidToType[BoolOID]}})
|
||||
@@ -349,20 +372,25 @@ func NewMap() *Map {
|
||||
registerDefaultPgTypeVariants[Circle](m, "circle")
|
||||
registerDefaultPgTypeVariants[Date](m, "date")
|
||||
registerDefaultPgTypeVariants[Range[Date]](m, "daterange")
|
||||
registerDefaultPgTypeVariants[Multirange[Range[Date]]](m, "datemultirange")
|
||||
registerDefaultPgTypeVariants[Float4](m, "float4")
|
||||
registerDefaultPgTypeVariants[Float8](m, "float8")
|
||||
registerDefaultPgTypeVariants[Range[Float8]](m, "numrange") // There is no PostgreSQL builtin float8range so map it to numrange.
|
||||
registerDefaultPgTypeVariants[Range[Float8]](m, "numrange") // There is no PostgreSQL builtin float8range so map it to numrange.
|
||||
registerDefaultPgTypeVariants[Multirange[Range[Float8]]](m, "nummultirange") // There is no PostgreSQL builtin float8multirange so map it to nummultirange.
|
||||
registerDefaultPgTypeVariants[Inet](m, "inet")
|
||||
registerDefaultPgTypeVariants[Int2](m, "int2")
|
||||
registerDefaultPgTypeVariants[Int4](m, "int4")
|
||||
registerDefaultPgTypeVariants[Range[Int4]](m, "int4range")
|
||||
registerDefaultPgTypeVariants[Multirange[Range[Int4]]](m, "int4multirange")
|
||||
registerDefaultPgTypeVariants[Int8](m, "int8")
|
||||
registerDefaultPgTypeVariants[Range[Int8]](m, "int8range")
|
||||
registerDefaultPgTypeVariants[Multirange[Range[Int8]]](m, "int8multirange")
|
||||
registerDefaultPgTypeVariants[Interval](m, "interval")
|
||||
registerDefaultPgTypeVariants[Line](m, "line")
|
||||
registerDefaultPgTypeVariants[Lseg](m, "lseg")
|
||||
registerDefaultPgTypeVariants[Numeric](m, "numeric")
|
||||
registerDefaultPgTypeVariants[Range[Numeric]](m, "numrange")
|
||||
registerDefaultPgTypeVariants[Multirange[Range[Numeric]]](m, "nummultirange")
|
||||
registerDefaultPgTypeVariants[Path](m, "path")
|
||||
registerDefaultPgTypeVariants[Point](m, "point")
|
||||
registerDefaultPgTypeVariants[Polygon](m, "polygon")
|
||||
@@ -372,7 +400,9 @@ func NewMap() *Map {
|
||||
registerDefaultPgTypeVariants[Timestamp](m, "timestamp")
|
||||
registerDefaultPgTypeVariants[Timestamptz](m, "timestamptz")
|
||||
registerDefaultPgTypeVariants[Range[Timestamp]](m, "tsrange")
|
||||
registerDefaultPgTypeVariants[Multirange[Range[Timestamp]]](m, "tsmultirange")
|
||||
registerDefaultPgTypeVariants[Range[Timestamptz]](m, "tstzrange")
|
||||
registerDefaultPgTypeVariants[Multirange[Range[Timestamptz]]](m, "tstzmultirange")
|
||||
registerDefaultPgTypeVariants[UUID](m, "uuid")
|
||||
|
||||
return m
|
||||
|
||||
Reference in New Issue
Block a user