Skip to content

Commit face192

Browse files
All known and nullable types support
1 parent f037378 commit face192

File tree

1 file changed

+68
-45
lines changed

1 file changed

+68
-45
lines changed

main.go

Lines changed: 68 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"context"
55
"encoding/binary"
6+
"errors"
67
"flag"
78
"fmt"
89
"os"
@@ -14,9 +15,11 @@ import (
1415
)
1516

1617
var (
17-
connStr string
18-
selGenericSQL string
19-
reqFlags = []string{"dsn", "sql"}
18+
connStr string
19+
selGenericSQL string
20+
reqFlags = []string{"dsn", "sql"}
21+
ci = pgtype.NewConnInfo()
22+
errUnsupportedOID = errors.New("unsupported OID")
2023
)
2124

2225
func init() {
@@ -54,6 +57,43 @@ func checkFlags() error {
5457
return nil
5558
}
5659

60+
// getRaw returns a raw bytes of value and a new type start.
61+
func getRaw(bytes []byte, start, len uint32) ([]byte, uint32) {
62+
if len == 0xFFFFFFFF {
63+
len = 0
64+
}
65+
66+
return bytes[start+8 : start+8+len], start + len + 8
67+
}
68+
69+
// scanRaw returns the value and a name of the type.
70+
func scanRaw(oid uint32, bytes []byte, len uint32) (value interface{}, name string, err error) {
71+
dt, ok := ci.DataTypeForOID(oid)
72+
if !ok {
73+
return nil, "", errUnsupportedOID
74+
}
75+
name = dt.Name
76+
77+
if len == 0xFFFFFFFF {
78+
value = "(NULL)"
79+
} else {
80+
if bd, ok := dt.Value.(pgtype.BinaryDecoder); ok {
81+
if err := bd.DecodeBinary(ci, bytes); err != nil {
82+
return nil, "", err
83+
}
84+
} else {
85+
return nil, "", fmt.Errorf("%T is not binary pgtype.BinaryDecoder", dt.Value)
86+
}
87+
88+
value = dt.Value.Get()
89+
if value == "(NULL)" {
90+
value = `"(NULL)"`
91+
}
92+
}
93+
94+
return
95+
}
96+
5797
func main() {
5898
flag.Parse()
5999
if err := checkFlags(); err != nil {
@@ -69,6 +109,16 @@ func main() {
69109
}
70110
defer pool.Close()
71111

112+
genericText := &pgtype.GenericText{}
113+
if err := pool.QueryRow(
114+
ctx,
115+
selGenericSQL,
116+
pgx.QueryResultFormats{pgx.TextFormatCode},
117+
).Scan(genericText); err != nil {
118+
fmt.Println(err)
119+
os.Exit(1)
120+
}
121+
72122
genericBinary := &pgtype.GenericBinary{}
73123
if err := pool.QueryRow(
74124
ctx,
@@ -79,6 +129,7 @@ func main() {
79129
os.Exit(1)
80130
}
81131

132+
fmt.Printf("Text: %v\n", genericText.String)
82133
fmt.Printf("Binary: %v\n", genericBinary.Bytes)
83134

84135
rawNumOfFields := genericBinary.Bytes[:4]
@@ -88,73 +139,45 @@ func main() {
88139
rawNumOfFields,
89140
numOfFieldsUint32,
90141
)
91-
ci := pgtype.NewConnInfo()
92142

93143
// The first 4 bytes are the number of fields - 2
94144
// Then for each field:
95145
// 4 bytes - OID
96146
// 4 bytes - length of value
97147
// x bytes - value
98-
typeStart := 4
148+
typeStart := uint32(4)
99149
for i := uint32(0); i < numOfFieldsUint32; i++ {
100150
rawOID := genericBinary.Bytes[typeStart : typeStart+4]
101151
oid := binary.BigEndian.Uint32(rawOID)
152+
102153
rawValLen := genericBinary.Bytes[typeStart+4 : typeStart+8]
103154
valLen := binary.BigEndian.Uint32(rawValLen)
104-
rawVal := genericBinary.Bytes[typeStart+8 : typeStart+8+int(valLen)]
105-
typeStart += int(valLen) + 8
106-
107-
var scanned interface{}
108-
var typeName string
109-
110-
switch oid {
111-
case pgtype.Int4OID:
112-
typeName = "int4 (int32)"
113-
var dst int32
114-
if err := ci.Scan(oid, pgtype.BinaryFormatCode, rawVal, &dst); err != nil {
115-
fmt.Println(err)
116-
os.Exit(1)
117-
}
118-
119-
scanned = dst
120-
121-
case pgtype.Float8OID:
122-
typeName = "float8 (double)"
123-
var dst float64
124-
if err := ci.Scan(oid, pgtype.BinaryFormatCode, rawVal, &dst); err != nil {
125-
fmt.Println(err)
126-
os.Exit(1)
127-
}
128155

129-
scanned = dst
156+
var rawVal []byte
157+
rawVal, typeStart = getRaw(genericBinary.Bytes, typeStart, valLen)
130158

131-
case pgtype.TextOID:
132-
typeName = "text"
133-
var dst string
134-
if err := ci.Scan(oid, pgtype.BinaryFormatCode, rawVal, &dst); err != nil {
159+
value, typeName, err := scanRaw(oid, rawVal, valLen)
160+
if err != nil {
161+
if !errors.Is(err, errUnsupportedOID) {
135162
fmt.Println(err)
136163
os.Exit(1)
137164
}
138165

139-
scanned = dst
140-
141-
default:
142-
typeName = "Unsupported"
143-
scanned = "Unsupported"
166+
value, typeName = "Unsupported", "Unsupported"
144167
}
145168

146169
fmt.Printf(
147170
`Field %d:
148-
OID: %d
171+
OID: %d (%v)
149172
Type %s
150-
Length: %d
151-
Value: %v
173+
Length: %d (%v)
174+
Value: %v (%v)
152175
`,
153176
i,
154-
oid,
177+
oid, rawOID,
155178
typeName,
156-
valLen,
157-
scanned,
179+
valLen, rawValLen,
180+
value, rawVal,
158181
)
159182
}
160183

0 commit comments

Comments
 (0)