This repository has been archived by the owner on Jul 29, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fastpath.go
108 lines (93 loc) · 2.25 KB
/
fastpath.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package pgx
import (
"encoding/binary"
)
func newFastpath(cn *Conn) *fastpath {
return &fastpath{cn: cn, fns: make(map[string]Oid)}
}
type fastpath struct {
cn *Conn
fns map[string]Oid
}
func (f *fastpath) functionOID(name string) Oid {
return f.fns[name]
}
func (f *fastpath) addFunction(name string, oid Oid) {
f.fns[name] = oid
}
func (f *fastpath) addFunctions(rows *Rows) error {
for rows.Next() {
var name string
var oid Oid
if err := rows.Scan(&name, &oid); err != nil {
return err
}
f.addFunction(name, oid)
}
return rows.Err()
}
type fpArg []byte
func fpIntArg(n int32) fpArg {
res := make([]byte, 4)
binary.BigEndian.PutUint32(res, uint32(n))
return res
}
func fpInt64Arg(n int64) fpArg {
res := make([]byte, 8)
binary.BigEndian.PutUint64(res, uint64(n))
return res
}
func (f *fastpath) Call(oid Oid, args []fpArg) (res []byte, err error) {
wbuf := newWriteBuf(f.cn, 'F') // function call
wbuf.WriteInt32(int32(oid)) // function object id
wbuf.WriteInt16(1) // # of argument format codes
wbuf.WriteInt16(1) // format code: binary
wbuf.WriteInt16(int16(len(args))) // # of arguments
for _, arg := range args {
wbuf.WriteInt32(int32(len(arg))) // length of argument
wbuf.WriteBytes(arg) // argument value
}
wbuf.WriteInt16(1) // response format code (binary)
wbuf.closeMsg()
if _, err := f.cn.conn.Write(wbuf.buf); err != nil {
return nil, err
}
for {
var t byte
var r *msgReader
t, r, err = f.cn.rxMsg()
if err != nil {
return nil, err
}
switch t {
case 'V': // FunctionCallResponse
data := r.readBytes(r.readInt32())
res = make([]byte, len(data))
copy(res, data)
case 'Z': // Ready for query
f.cn.rxReadyForQuery(r)
// done
return
default:
if err := f.cn.processContextFreeMsg(t, r); err != nil {
return nil, err
}
}
}
}
func (f *fastpath) CallFn(fn string, args []fpArg) ([]byte, error) {
return f.Call(f.functionOID(fn), args)
}
func fpInt32(data []byte, err error) (int32, error) {
if err != nil {
return 0, err
}
n := int32(binary.BigEndian.Uint32(data))
return n, nil
}
func fpInt64(data []byte, err error) (int64, error) {
if err != nil {
return 0, err
}
return int64(binary.BigEndian.Uint64(data)), nil
}