2
0

Build / rewrite / port multirange support

This commit is contained in:
Jack Christensen
2022-04-23 12:50:18 -05:00
parent 126b582f19
commit dfb681d716
3 changed files with 677 additions and 92 deletions
+443
View File
@@ -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)
}
+112
View File
@@ -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
View File
@@ -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