pgx/pgtype/pgtype.go

281 lines
7.6 KiB
Go

package pgtype
import (
"reflect"
"github.com/pkg/errors"
)
// PostgreSQL oids for common types
const (
BoolOID = 16
ByteaOID = 17
CharOID = 18
NameOID = 19
Int8OID = 20
Int2OID = 21
Int4OID = 23
TextOID = 25
OIDOID = 26
TIDOID = 27
XIDOID = 28
CIDOID = 29
JSONOID = 114
CIDROID = 650
CIDRArrayOID = 651
Float4OID = 700
Float8OID = 701
UnknownOID = 705
InetOID = 869
BoolArrayOID = 1000
Int2ArrayOID = 1005
Int4ArrayOID = 1007
TextArrayOID = 1009
ByteaArrayOID = 1001
BPCharArrayOID = 1014
VarcharArrayOID = 1015
Int8ArrayOID = 1016
Float4ArrayOID = 1021
Float8ArrayOID = 1022
ACLItemOID = 1033
ACLItemArrayOID = 1034
InetArrayOID = 1041
BPCharOID = 1042
VarcharOID = 1043
DateOID = 1082
TimestampOID = 1114
TimestampArrayOID = 1115
DateArrayOID = 1182
TimestamptzOID = 1184
TimestamptzArrayOID = 1185
NumericOID = 1700
RecordOID = 2249
UUIDOID = 2950
UUIDArrayOID = 2951
JSONBOID = 3802
)
type Status byte
const (
Undefined Status = iota
Null
Present
)
type InfinityModifier int8
const (
Infinity InfinityModifier = 1
None InfinityModifier = 0
NegativeInfinity InfinityModifier = -Infinity
)
func (im InfinityModifier) String() string {
switch im {
case None:
return "none"
case Infinity:
return "infinity"
case NegativeInfinity:
return "-infinity"
default:
return "invalid"
}
}
type Value interface {
// Set converts and assigns src to itself.
Set(src interface{}) error
// Get returns the simplest representation of Value. If the Value is Null or
// Undefined that is the return value. If no simpler representation is
// possible, then Get() returns Value.
Get() interface{}
// AssignTo converts and assigns the Value to dst. It MUST make a deep copy of
// any reference types.
AssignTo(dst interface{}) error
}
type BinaryDecoder interface {
// DecodeBinary decodes src into BinaryDecoder. If src is nil then the
// original SQL value is NULL. BinaryDecoder takes ownership of src. The
// caller MUST not use it again.
DecodeBinary(ci *ConnInfo, src []byte) error
}
type TextDecoder interface {
// DecodeText decodes src into TextDecoder. If src is nil then the original
// SQL value is NULL. TextDecoder takes ownership of src. The caller MUST not
// use it again.
DecodeText(ci *ConnInfo, src []byte) error
}
// BinaryEncoder is implemented by types that can encode themselves into the
// PostgreSQL binary wire format.
type BinaryEncoder interface {
// EncodeBinary should append the binary format of self to buf. If self is the
// SQL value NULL then append nothing and return (nil, nil). The caller of
// EncodeBinary is responsible for writing the correct NULL value or the
// length of the data written.
EncodeBinary(ci *ConnInfo, buf []byte) (newBuf []byte, err error)
}
// TextEncoder is implemented by types that can encode themselves into the
// PostgreSQL text wire format.
type TextEncoder interface {
// EncodeText should append the text format of self to buf. If self is the
// SQL value NULL then append nothing and return (nil, nil). The caller of
// EncodeText is responsible for writing the correct NULL value or the
// length of the data written.
EncodeText(ci *ConnInfo, buf []byte) (newBuf []byte, err error)
}
var errUndefined = errors.New("cannot encode status undefined")
var errBadStatus = errors.New("invalid status")
type DataType struct {
Value Value
Name string
OID OID
}
type ConnInfo struct {
oidToDataType map[OID]*DataType
nameToDataType map[string]*DataType
reflectTypeToDataType map[reflect.Type]*DataType
}
func NewConnInfo() *ConnInfo {
return &ConnInfo{
oidToDataType: make(map[OID]*DataType, 256),
nameToDataType: make(map[string]*DataType, 256),
reflectTypeToDataType: make(map[reflect.Type]*DataType, 256),
}
}
func (ci *ConnInfo) InitializeDataTypes(nameOIDs map[string]OID) {
for name, oid := range nameOIDs {
var value Value
if t, ok := nameValues[name]; ok {
value = reflect.New(reflect.ValueOf(t).Elem().Type()).Interface().(Value)
} else {
value = &GenericText{}
}
ci.RegisterDataType(DataType{Value: value, Name: name, OID: oid})
}
}
func (ci *ConnInfo) RegisterDataType(t DataType) {
ci.oidToDataType[t.OID] = &t
ci.nameToDataType[t.Name] = &t
ci.reflectTypeToDataType[reflect.ValueOf(t.Value).Type()] = &t
}
func (ci *ConnInfo) DataTypeForOID(oid OID) (*DataType, bool) {
dt, ok := ci.oidToDataType[oid]
return dt, ok
}
func (ci *ConnInfo) DataTypeForName(name string) (*DataType, bool) {
dt, ok := ci.nameToDataType[name]
return dt, ok
}
func (ci *ConnInfo) DataTypeForValue(v Value) (*DataType, bool) {
dt, ok := ci.reflectTypeToDataType[reflect.ValueOf(v).Type()]
return dt, ok
}
// DeepCopy makes a deep copy of the ConnInfo.
func (ci *ConnInfo) DeepCopy() *ConnInfo {
ci2 := &ConnInfo{
oidToDataType: make(map[OID]*DataType, len(ci.oidToDataType)),
nameToDataType: make(map[string]*DataType, len(ci.nameToDataType)),
reflectTypeToDataType: make(map[reflect.Type]*DataType, len(ci.reflectTypeToDataType)),
}
for _, dt := range ci.oidToDataType {
ci2.RegisterDataType(DataType{
Value: reflect.New(reflect.ValueOf(dt.Value).Elem().Type()).Interface().(Value),
Name: dt.Name,
OID: dt.OID,
})
}
return ci2
}
var nameValues map[string]Value
func init() {
nameValues = map[string]Value{
"_aclitem": &ACLItemArray{},
"_bool": &BoolArray{},
"_bpchar": &BPCharArray{},
"_bytea": &ByteaArray{},
"_cidr": &CIDRArray{},
"_date": &DateArray{},
"_float4": &Float4Array{},
"_float8": &Float8Array{},
"_inet": &InetArray{},
"_int2": &Int2Array{},
"_int4": &Int4Array{},
"_int8": &Int8Array{},
"_numeric": &NumericArray{},
"_text": &TextArray{},
"_timestamp": &TimestampArray{},
"_timestamptz": &TimestamptzArray{},
"_uuid": &UUIDArray{},
"_varchar": &VarcharArray{},
"aclitem": &ACLItem{},
"bit": &Bit{},
"bool": &Bool{},
"box": &Box{},
"bpchar": &BPChar{},
"bytea": &Bytea{},
"char": &QChar{},
"cid": &CID{},
"cidr": &CIDR{},
"circle": &Circle{},
"date": &Date{},
"daterange": &Daterange{},
"decimal": &Decimal{},
"float4": &Float4{},
"float8": &Float8{},
"hstore": &Hstore{},
"inet": &Inet{},
"int2": &Int2{},
"int4": &Int4{},
"int4range": &Int4range{},
"int8": &Int8{},
"int8range": &Int8range{},
"interval": &Interval{},
"json": &JSON{},
"jsonb": &JSONB{},
"line": &Line{},
"lseg": &Lseg{},
"macaddr": &Macaddr{},
"name": &Name{},
"numeric": &Numeric{},
"numrange": &Numrange{},
"oid": &OIDValue{},
"path": &Path{},
"point": &Point{},
"polygon": &Polygon{},
"record": &Record{},
"text": &Text{},
"tid": &TID{},
"timestamp": &Timestamp{},
"timestamptz": &Timestamptz{},
"tsrange": &Tsrange{},
"tstzrange": &Tstzrange{},
"unknown": &Unknown{},
"uuid": &UUID{},
"varbit": &Varbit{},
"varchar": &Varchar{},
"xid": &XID{},
}
}