1package pgtype 2 3import ( 4 "reflect" 5 6 "github.com/pkg/errors" 7) 8 9// PostgreSQL oids for common types 10const ( 11 BoolOID = 16 12 ByteaOID = 17 13 CharOID = 18 14 NameOID = 19 15 Int8OID = 20 16 Int2OID = 21 17 Int4OID = 23 18 TextOID = 25 19 OIDOID = 26 20 TIDOID = 27 21 XIDOID = 28 22 CIDOID = 29 23 JSONOID = 114 24 CIDROID = 650 25 CIDRArrayOID = 651 26 Float4OID = 700 27 Float8OID = 701 28 UnknownOID = 705 29 InetOID = 869 30 BoolArrayOID = 1000 31 Int2ArrayOID = 1005 32 Int4ArrayOID = 1007 33 TextArrayOID = 1009 34 ByteaArrayOID = 1001 35 BPCharArrayOID = 1014 36 VarcharArrayOID = 1015 37 Int8ArrayOID = 1016 38 Float4ArrayOID = 1021 39 Float8ArrayOID = 1022 40 ACLItemOID = 1033 41 ACLItemArrayOID = 1034 42 InetArrayOID = 1041 43 BPCharOID = 1042 44 VarcharOID = 1043 45 DateOID = 1082 46 TimestampOID = 1114 47 TimestampArrayOID = 1115 48 DateArrayOID = 1182 49 TimestamptzOID = 1184 50 TimestamptzArrayOID = 1185 51 NumericOID = 1700 52 RecordOID = 2249 53 UUIDOID = 2950 54 UUIDArrayOID = 2951 55 JSONBOID = 3802 56) 57 58type Status byte 59 60const ( 61 Undefined Status = iota 62 Null 63 Present 64) 65 66type InfinityModifier int8 67 68const ( 69 Infinity InfinityModifier = 1 70 None InfinityModifier = 0 71 NegativeInfinity InfinityModifier = -Infinity 72) 73 74func (im InfinityModifier) String() string { 75 switch im { 76 case None: 77 return "none" 78 case Infinity: 79 return "infinity" 80 case NegativeInfinity: 81 return "-infinity" 82 default: 83 return "invalid" 84 } 85} 86 87type Value interface { 88 // Set converts and assigns src to itself. 89 Set(src interface{}) error 90 91 // Get returns the simplest representation of Value. If the Value is Null or 92 // Undefined that is the return value. If no simpler representation is 93 // possible, then Get() returns Value. 94 Get() interface{} 95 96 // AssignTo converts and assigns the Value to dst. It MUST make a deep copy of 97 // any reference types. 98 AssignTo(dst interface{}) error 99} 100 101type BinaryDecoder interface { 102 // DecodeBinary decodes src into BinaryDecoder. If src is nil then the 103 // original SQL value is NULL. BinaryDecoder takes ownership of src. The 104 // caller MUST not use it again. 105 DecodeBinary(ci *ConnInfo, src []byte) error 106} 107 108type TextDecoder interface { 109 // DecodeText decodes src into TextDecoder. If src is nil then the original 110 // SQL value is NULL. TextDecoder takes ownership of src. The caller MUST not 111 // use it again. 112 DecodeText(ci *ConnInfo, src []byte) error 113} 114 115// BinaryEncoder is implemented by types that can encode themselves into the 116// PostgreSQL binary wire format. 117type BinaryEncoder interface { 118 // EncodeBinary should append the binary format of self to buf. If self is the 119 // SQL value NULL then append nothing and return (nil, nil). The caller of 120 // EncodeBinary is responsible for writing the correct NULL value or the 121 // length of the data written. 122 EncodeBinary(ci *ConnInfo, buf []byte) (newBuf []byte, err error) 123} 124 125// TextEncoder is implemented by types that can encode themselves into the 126// PostgreSQL text wire format. 127type TextEncoder interface { 128 // EncodeText should append the text format of self to buf. If self is the 129 // SQL value NULL then append nothing and return (nil, nil). The caller of 130 // EncodeText is responsible for writing the correct NULL value or the 131 // length of the data written. 132 EncodeText(ci *ConnInfo, buf []byte) (newBuf []byte, err error) 133} 134 135var errUndefined = errors.New("cannot encode status undefined") 136var errBadStatus = errors.New("invalid status") 137 138type DataType struct { 139 Value Value 140 Name string 141 OID OID 142} 143 144type ConnInfo struct { 145 oidToDataType map[OID]*DataType 146 nameToDataType map[string]*DataType 147 reflectTypeToDataType map[reflect.Type]*DataType 148} 149 150func NewConnInfo() *ConnInfo { 151 return &ConnInfo{ 152 oidToDataType: make(map[OID]*DataType, 256), 153 nameToDataType: make(map[string]*DataType, 256), 154 reflectTypeToDataType: make(map[reflect.Type]*DataType, 256), 155 } 156} 157 158func (ci *ConnInfo) InitializeDataTypes(nameOIDs map[string]OID) { 159 for name, oid := range nameOIDs { 160 var value Value 161 if t, ok := nameValues[name]; ok { 162 value = reflect.New(reflect.ValueOf(t).Elem().Type()).Interface().(Value) 163 } else { 164 value = &GenericText{} 165 } 166 ci.RegisterDataType(DataType{Value: value, Name: name, OID: oid}) 167 } 168} 169 170func (ci *ConnInfo) RegisterDataType(t DataType) { 171 ci.oidToDataType[t.OID] = &t 172 ci.nameToDataType[t.Name] = &t 173 ci.reflectTypeToDataType[reflect.ValueOf(t.Value).Type()] = &t 174} 175 176func (ci *ConnInfo) DataTypeForOID(oid OID) (*DataType, bool) { 177 dt, ok := ci.oidToDataType[oid] 178 return dt, ok 179} 180 181func (ci *ConnInfo) DataTypeForName(name string) (*DataType, bool) { 182 dt, ok := ci.nameToDataType[name] 183 return dt, ok 184} 185 186func (ci *ConnInfo) DataTypeForValue(v Value) (*DataType, bool) { 187 dt, ok := ci.reflectTypeToDataType[reflect.ValueOf(v).Type()] 188 return dt, ok 189} 190 191// DeepCopy makes a deep copy of the ConnInfo. 192func (ci *ConnInfo) DeepCopy() *ConnInfo { 193 ci2 := &ConnInfo{ 194 oidToDataType: make(map[OID]*DataType, len(ci.oidToDataType)), 195 nameToDataType: make(map[string]*DataType, len(ci.nameToDataType)), 196 reflectTypeToDataType: make(map[reflect.Type]*DataType, len(ci.reflectTypeToDataType)), 197 } 198 199 for _, dt := range ci.oidToDataType { 200 ci2.RegisterDataType(DataType{ 201 Value: reflect.New(reflect.ValueOf(dt.Value).Elem().Type()).Interface().(Value), 202 Name: dt.Name, 203 OID: dt.OID, 204 }) 205 } 206 207 return ci2 208} 209 210var nameValues map[string]Value 211 212func init() { 213 nameValues = map[string]Value{ 214 "_aclitem": &ACLItemArray{}, 215 "_bool": &BoolArray{}, 216 "_bpchar": &BPCharArray{}, 217 "_bytea": &ByteaArray{}, 218 "_cidr": &CIDRArray{}, 219 "_date": &DateArray{}, 220 "_float4": &Float4Array{}, 221 "_float8": &Float8Array{}, 222 "_inet": &InetArray{}, 223 "_int2": &Int2Array{}, 224 "_int4": &Int4Array{}, 225 "_int8": &Int8Array{}, 226 "_numeric": &NumericArray{}, 227 "_text": &TextArray{}, 228 "_timestamp": &TimestampArray{}, 229 "_timestamptz": &TimestamptzArray{}, 230 "_uuid": &UUIDArray{}, 231 "_varchar": &VarcharArray{}, 232 "aclitem": &ACLItem{}, 233 "bit": &Bit{}, 234 "bool": &Bool{}, 235 "box": &Box{}, 236 "bpchar": &BPChar{}, 237 "bytea": &Bytea{}, 238 "char": &QChar{}, 239 "cid": &CID{}, 240 "cidr": &CIDR{}, 241 "circle": &Circle{}, 242 "date": &Date{}, 243 "daterange": &Daterange{}, 244 "decimal": &Decimal{}, 245 "float4": &Float4{}, 246 "float8": &Float8{}, 247 "hstore": &Hstore{}, 248 "inet": &Inet{}, 249 "int2": &Int2{}, 250 "int4": &Int4{}, 251 "int4range": &Int4range{}, 252 "int8": &Int8{}, 253 "int8range": &Int8range{}, 254 "interval": &Interval{}, 255 "json": &JSON{}, 256 "jsonb": &JSONB{}, 257 "line": &Line{}, 258 "lseg": &Lseg{}, 259 "macaddr": &Macaddr{}, 260 "name": &Name{}, 261 "numeric": &Numeric{}, 262 "numrange": &Numrange{}, 263 "oid": &OIDValue{}, 264 "path": &Path{}, 265 "point": &Point{}, 266 "polygon": &Polygon{}, 267 "record": &Record{}, 268 "text": &Text{}, 269 "tid": &TID{}, 270 "timestamp": &Timestamp{}, 271 "timestamptz": &Timestamptz{}, 272 "tsrange": &Tsrange{}, 273 "tstzrange": &Tstzrange{}, 274 "unknown": &Unknown{}, 275 "uuid": &UUID{}, 276 "varbit": &Varbit{}, 277 "varchar": &Varchar{}, 278 "xid": &XID{}, 279 } 280} 281