forked from fl00r/go-tarantool-1.6
-
Notifications
You must be signed in to change notification settings - Fork 59
/
prepared.go
196 lines (171 loc) · 5.54 KB
/
prepared.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package tarantool
import (
"context"
"fmt"
"io"
"github.com/tarantool/go-iproto"
"github.com/vmihailenco/msgpack/v5"
)
// PreparedID is a type for Prepared Statement ID
type PreparedID uint64
// Prepared is a type for handling prepared statements
//
// Since 1.7.0
type Prepared struct {
StatementID PreparedID
MetaData []ColumnMetaData
ParamCount uint64
Conn *Connection
}
func fillPrepare(enc *msgpack.Encoder, expr string) error {
enc.EncodeMapLen(1)
enc.EncodeUint(uint64(iproto.IPROTO_SQL_TEXT))
return enc.EncodeString(expr)
}
func fillUnprepare(enc *msgpack.Encoder, stmt Prepared) error {
enc.EncodeMapLen(1)
enc.EncodeUint(uint64(iproto.IPROTO_STMT_ID))
return enc.EncodeUint(uint64(stmt.StatementID))
}
func fillExecutePrepared(enc *msgpack.Encoder, stmt Prepared, args interface{}) error {
enc.EncodeMapLen(2)
enc.EncodeUint(uint64(iproto.IPROTO_STMT_ID))
enc.EncodeUint(uint64(stmt.StatementID))
enc.EncodeUint(uint64(iproto.IPROTO_SQL_BIND))
return encodeSQLBind(enc, args)
}
// NewPreparedFromResponse constructs a Prepared object.
func NewPreparedFromResponse(conn *Connection, resp Response) (*Prepared, error) {
if resp == nil {
return nil, fmt.Errorf("passed nil response")
}
data, err := resp.Decode()
if err != nil {
return nil, fmt.Errorf("decode response body error: %s", err.Error())
}
if data == nil {
return nil, fmt.Errorf("response Data is nil")
}
if len(data) == 0 {
return nil, fmt.Errorf("response Data format is wrong")
}
stmt, ok := data[0].(*Prepared)
if !ok {
return nil, fmt.Errorf("response Data format is wrong")
}
stmt.Conn = conn
return stmt, nil
}
// PrepareRequest helps you to create a prepare request object for execution
// by a Connection.
type PrepareRequest struct {
baseRequest
expr string
}
// NewPrepareRequest returns a new empty PrepareRequest.
func NewPrepareRequest(expr string) *PrepareRequest {
req := new(PrepareRequest)
req.rtype = iproto.IPROTO_PREPARE
req.expr = expr
return req
}
// Body fills an msgpack.Encoder with the execute request body.
func (req *PrepareRequest) Body(res SchemaResolver, enc *msgpack.Encoder) error {
return fillPrepare(enc, req.expr)
}
// Context sets a passed context to the request.
//
// Pay attention that when using context with request objects,
// the timeout option for Connection does not affect the lifetime
// of the request. For those purposes use context.WithTimeout() as
// the root context.
func (req *PrepareRequest) Context(ctx context.Context) *PrepareRequest {
req.ctx = ctx
return req
}
// Response creates a response for the PrepareRequest.
func (req *PrepareRequest) Response(header Header, body io.Reader) (Response, error) {
baseResp, err := createBaseResponse(header, body)
if err != nil {
return nil, err
}
return &PrepareResponse{baseResponse: baseResp}, nil
}
// UnprepareRequest helps you to create an unprepare request object for
// execution by a Connection.
type UnprepareRequest struct {
baseRequest
stmt *Prepared
}
// NewUnprepareRequest returns a new empty UnprepareRequest.
func NewUnprepareRequest(stmt *Prepared) *UnprepareRequest {
req := new(UnprepareRequest)
req.rtype = iproto.IPROTO_PREPARE
req.stmt = stmt
return req
}
// Conn returns the Connection object the request belongs to
func (req *UnprepareRequest) Conn() *Connection {
return req.stmt.Conn
}
// Body fills an msgpack.Encoder with the execute request body.
func (req *UnprepareRequest) Body(res SchemaResolver, enc *msgpack.Encoder) error {
return fillUnprepare(enc, *req.stmt)
}
// Context sets a passed context to the request.
//
// Pay attention that when using context with request objects,
// the timeout option for Connection does not affect the lifetime
// of the request. For those purposes use context.WithTimeout() as
// the root context.
func (req *UnprepareRequest) Context(ctx context.Context) *UnprepareRequest {
req.ctx = ctx
return req
}
// ExecutePreparedRequest helps you to create an execute prepared request
// object for execution by a Connection.
type ExecutePreparedRequest struct {
baseRequest
stmt *Prepared
args interface{}
}
// NewExecutePreparedRequest returns a new empty preparedExecuteRequest.
func NewExecutePreparedRequest(stmt *Prepared) *ExecutePreparedRequest {
req := new(ExecutePreparedRequest)
req.rtype = iproto.IPROTO_EXECUTE
req.stmt = stmt
req.args = []interface{}{}
return req
}
// Conn returns the Connection object the request belongs to
func (req *ExecutePreparedRequest) Conn() *Connection {
return req.stmt.Conn
}
// Args sets the args for execute the prepared request.
// Note: default value is empty.
func (req *ExecutePreparedRequest) Args(args interface{}) *ExecutePreparedRequest {
req.args = args
return req
}
// Body fills an msgpack.Encoder with the execute request body.
func (req *ExecutePreparedRequest) Body(res SchemaResolver, enc *msgpack.Encoder) error {
return fillExecutePrepared(enc, *req.stmt, req.args)
}
// Context sets a passed context to the request.
//
// Pay attention that when using context with request objects,
// the timeout option for Connection does not affect the lifetime
// of the request. For those purposes use context.WithTimeout() as
// the root context.
func (req *ExecutePreparedRequest) Context(ctx context.Context) *ExecutePreparedRequest {
req.ctx = ctx
return req
}
// Response creates a response for the ExecutePreparedRequest.
func (req *ExecutePreparedRequest) Response(header Header, body io.Reader) (Response, error) {
baseResp, err := createBaseResponse(header, body)
if err != nil {
return nil, err
}
return &ExecuteResponse{baseResponse: baseResp}, nil
}