forked from go-sql-driver/mysql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstatement.go
More file actions
211 lines (182 loc) · 5.51 KB
/
statement.go
File metadata and controls
211 lines (182 loc) · 5.51 KB
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Go MySQL Sürücüsü - Go'nun database/sql paketi için bir MySQL Sürücüsü
//
// 2012 Go-MySQL-Driver Yazarlarının Tüm Hakları Saklıdır.
//
// Bu Kaynak Kod Formu, Mozilla Genel Kamu Lisansı, v. 2.0 şartlarına tabidir.
// Bu dosya ile birlikte MPL'nin bir kopyası dağıtılmadıysa,
// http://mozilla.org/MPL/2.0/ adresinden edinebilirsiniz.
package mysql
import (
"database/sql/driver"
"encoding/json"
"fmt"
"io"
"reflect"
)
type mysqlStmt struct {
mc *mysqlConn
id uint32
paramCount int
}
func (stmt *mysqlStmt) Close() error {
if stmt.mc == nil || stmt.mc.closed.Load() {
// driver.Stmt.Close birden fazla kez çağrılabilir, bu nedenle bu fonksiyon
// idempotent olmalıdır. Ayrıca Bkz. Issue #450 ve golang/go#16019.
// Bu hata Go 1.8'de düzeltildi.
// https://github.com/golang/go/commit/90b8a0ca2d0b565c7c7199ffcf77b15ea6b6db3a
// Ancak bu fonksiyonu idempotent tutmak daha güvenlidir.
return nil
}
err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id)
stmt.mc = nil
return err
}
func (stmt *mysqlStmt) NumInput() int {
return stmt.paramCount
}
func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter {
return converter{}
}
func (stmt *mysqlStmt) CheckNamedValue(nv *driver.NamedValue) (err error) {
nv.Value, err = converter{}.ConvertValue(nv.Value)
return
}
func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
if stmt.mc.closed.Load() {
return nil, driver.ErrBadConn
}
// Komutu gönder
err := stmt.writeExecutePacket(args)
if err != nil {
return nil, stmt.mc.markBadConn(err)
}
mc := stmt.mc
handleOk := stmt.mc.clearResult()
// Sonucu Oku
resLen, err := handleOk.readResultSetHeaderPacket()
if err != nil {
return nil, err
}
if resLen > 0 {
// Sütunlar
if err = mc.readUntilEOF(); err != nil {
return nil, err
}
// Satırlar
if err := mc.readUntilEOF(); err != nil {
return nil, err
}
}
if err := handleOk.discardResults(); err != nil {
return nil, err
}
copied := mc.result
return &copied, nil
}
func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
return stmt.query(args)
}
func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
if stmt.mc.closed.Load() {
return nil, driver.ErrBadConn
}
// Komutu gönder
err := stmt.writeExecutePacket(args)
if err != nil {
return nil, stmt.mc.markBadConn(err)
}
mc := stmt.mc
// Sonucu Oku
handleOk := stmt.mc.clearResult()
resLen, err := handleOk.readResultSetHeaderPacket()
if err != nil {
return nil, err
}
rows := new(binaryRows)
if resLen > 0 {
rows.mc = mc
rows.rs.columns, err = mc.readColumns(resLen)
} else {
rows.rs.done = true
switch err := rows.NextResultSet(); err {
case nil, io.EOF:
return rows, nil
default:
return nil, err
}
}
return rows, err
}
var jsonType = reflect.TypeOf(json.RawMessage{})
type converter struct{}
// ConvertValue, database/sql/driver'daki referans/varsayılan dönüştürücüyü
// bir _istisna_ ile yansıtır. Yüksek biti olan uint64'ü destekleriz ve varsayılan
// implementasyon bunu yapmaz. Bu fonksiyon, deliberate fark dışında
// database/sql/driver defaultConverter.ConvertValue() ile senkronize tutulmalıdır.
func (c converter) ConvertValue(v any) (driver.Value, error) {
if driver.IsValue(v) {
return v, nil
}
if vr, ok := v.(driver.Valuer); ok {
sv, err := callValuerValue(vr)
if err != nil {
return nil, err
}
if driver.IsValue(sv) {
return sv, nil
}
// Valuer arayüzünden dönen bir değer, "bir veritabanı sürücüsünün NamedValueChecker arayüzü tarafından işlenen bir tür" olabilir, bu yüzden burada uint64'ü de kabul etmeliyiz.
if u, ok := sv.(uint64); ok {
return u, nil
}
return nil, fmt.Errorf("Value arayüzünden dönen geçersiz tür %T", sv)
}
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Ptr:
// pointerları dolaylı olarak işleme
if rv.IsNil() {
return nil, nil
} else {
return c.ConvertValue(rv.Elem().Interface())
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return rv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return rv.Uint(), nil
case reflect.Float32, reflect.Float64:
return rv.Float(), nil
case reflect.Bool:
return rv.Bool(), nil
case reflect.Slice:
switch t := rv.Type(); {
case t == jsonType:
return v, nil
case t.Elem().Kind() == reflect.Uint8:
return rv.Bytes(), nil
default:
return nil, fmt.Errorf("desteklenmeyen tür %T, %s dilim", v, t.Elem().Kind())
}
case reflect.String:
return rv.String(), nil
}
return nil, fmt.Errorf("desteklenmeyen tür %T, %s", v, rv.Kind())
}
var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
// callValuerValue, vr.Value()'ı döndürür, bir istisna ile:
// Eğer vr.Value bir pointer türünde otomatik oluşturulmuş bir metodsa ve
// pointer nil ise, panicwrap metodunda çalışma zamanında panik yapar.
// Bunu nil olarak kabul edin.
//
// Bu, insanlar değer türlerinde driver.Value uygulayabilsinler ve
// bu türlerin nil pointerlarını nil/NULL anlamına gelecek şekilde kullanabilsinler diye yapılmıştır, tıpkı string/*string gibi.
//
// Bu, database/sql paketindeki aynı isimli dışa kapalı fonksiyonun tam bir kopyasıdır.
func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
rv.IsNil() &&
rv.Type().Elem().Implements(valuerReflectType) {
return nil, nil
}
return vr.Value()
}