Skip to content

Commit d0b7ff1

Browse files
author
Phil Bayfield
committed
added fetch/extra conversion functions
1 parent 51a0507 commit d0b7ff1

File tree

4 files changed

+143
-16
lines changed

4 files changed

+143
-16
lines changed

convert.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,48 @@ func lcbtob(n uint64) (b []byte) {
213213
// <= 0xffffff = 253 + 3 bytes
214214
case n <= 0xffffff:
215215
b = []byte{0xfd, byte(n), byte(n >> 8), byte(n >> 16)}
216+
// Due to max packet size the 8 byte version is never actually used so is ommited
217+
}
218+
return
219+
}
220+
221+
// any to uint64
222+
func atou64(i interface{}) (n uint64) {
223+
switch t := i.(type) {
224+
case int: n = uint64(t)
225+
case uint: n = uint64(t)
226+
case int8: n = uint64(t)
227+
case uint8: n = uint64(t)
228+
case int16: n = uint64(t)
229+
case uint16: n = uint64(t)
230+
case int32: n = uint64(t)
231+
case uint32: n = uint64(t)
232+
case int64: n = uint64(t)
233+
case uint64: return t
234+
default:
235+
panic("Not a numeric type")
236+
}
237+
return
238+
}
239+
240+
// any to float64
241+
func atof64(i interface{}) (f float64) {
242+
switch t := i.(type) {
243+
case float32: f = float64(t)
244+
case float64: return t
245+
default:
246+
panic("Not a floating point type")
247+
}
248+
return
249+
}
250+
251+
// any to string
252+
func atos(i interface{}) (s string) {
253+
switch t:= i.(type) {
254+
case []byte: s = string(t)
255+
case string: return t
256+
default:
257+
panic("Not a string or compatible type")
216258
}
217259
return
218260
}

handler.go

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -177,67 +177,68 @@ func handleBinaryRow(p *packetRowBinary, c *Client, r *Result) (err os.Error) {
177177
}
178178
// Read data into fields
179179
var row []interface{}
180+
var field interface{}
180181
// Get null bit map
181182
nc := (r.fieldCount + 9) / 8
182-
nbm := p.data[0:nc]
183-
pos := nc
183+
nbm := p.data[1:nc+1]
184+
pos := nc + 1
184185
for i, f := range r.fields {
185186
// Check if field is null
186187
posByte := (i + 2) / 8
187188
posBit := i - (posByte * 8) + 2
188189
if nbm[posByte]&(1<<uint8(posBit)) != 0 {
189-
row = append(row, nil)
190+
field = nil
190191
continue
191192
}
192193
// Otherwise use field type
193194
switch f.Type {
194195
// Tiny int (8 bit int unsigned or signed)
195196
case FIELD_TYPE_TINY:
196197
if f.Flags&FLAG_UNSIGNED > 0 {
197-
row = append(row, p.data[pos])
198+
field = p.data[pos]
198199
} else {
199-
row = append(row, int8(p.data[pos]))
200+
field = int8(p.data[pos])
200201
}
201202
pos++
202203
// Small int (16 bit int unsigned or signed)
203204
case FIELD_TYPE_SHORT, FIELD_TYPE_YEAR:
204205
if f.Flags&FLAG_UNSIGNED > 0 {
205-
row = append(row, btoui16(p.data[pos:pos+2]))
206+
field = btoui16(p.data[pos:pos+2])
206207
} else {
207-
row = append(row, btoi16(p.data[pos:pos+2]))
208+
field = btoi16(p.data[pos:pos+2])
208209
}
209210
pos += 2
210211
// Int (32 bit int unsigned or signed) and medium int which is actually in int32 format
211212
case FIELD_TYPE_LONG, FIELD_TYPE_INT24:
212213
if f.Flags&FLAG_UNSIGNED > 0 {
213-
row = append(row, btoui32(p.data[pos:pos+4]))
214+
field = btoui32(p.data[pos:pos+4])
214215
} else {
215-
row = append(row, btoi32(p.data[pos:pos+4]))
216+
field = btoi32(p.data[pos:pos+4])
216217
}
217218
pos += 4
218219
// Big int (64 bit int unsigned or signed)
219220
case FIELD_TYPE_LONGLONG:
220221
if f.Flags&FLAG_UNSIGNED > 0 {
221-
row = append(row, btoui64(p.data[pos:pos+8]))
222+
field = btoui64(p.data[pos:pos+8])
222223
} else {
223-
row = append(row, btoi64(p.data[pos:pos+8]))
224+
field = btoi64(p.data[pos:pos+8])
224225
}
225226
pos += 8
226227
// Floats (Single precision floating point, 32 bit signed)
227228
case FIELD_TYPE_FLOAT:
228-
row = append(row, btof32(p.data[pos:pos+4]))
229+
field = btof32(p.data[pos:pos+4])
229230
pos += 4
230231
// Double (Double precision floating point, 64 bit signed)
231232
case FIELD_TYPE_DOUBLE:
232-
row = append(row, btof64(p.data[pos:pos+8]))
233+
field = btof64(p.data[pos:pos+8])
233234
pos += 8
234235
// Bit, decimal, strings, blobs etc, all length coded binary strings
235236
case FIELD_TYPE_BIT, FIELD_TYPE_DECIMAL, FIELD_TYPE_NEWDECIMAL, FIELD_TYPE_VARCHAR, FIELD_TYPE_TINY_BLOB, FIELD_TYPE_MEDIUM_BLOB, FIELD_TYPE_LONG_BLOB, FIELD_TYPE_BLOB, FIELD_TYPE_VAR_STRING, FIELD_TYPE_STRING, FIELD_TYPE_GEOMETRY:
236237
num, n, err := btolcb(p.data[pos:])
237238
if err != nil {
238239
return
239240
}
240-
row = append(row, p.data[pos+uint64(n):pos+uint64(n)+num])
241+
field = p.data[pos+uint64(n):pos+uint64(n)+num]
241242
pos += uint64(n) + num
242243
// Date/Datetime/Timestamp YYYY-MM-DD HH:MM:SS (From libmysql/libmysql.c read_binary_datetime)
243244
case FIELD_TYPE_DATE, FIELD_TYPE_TIMESTAMP, FIELD_TYPE_DATETIME:
@@ -246,6 +247,8 @@ func handleBinaryRow(p *packetRowBinary, c *Client, r *Result) (err os.Error) {
246247
case FIELD_TYPE_TIME:
247248
// @todo
248249
}
250+
// Add to row
251+
row = append(row, field)
249252
}
250253
// Stored result
251254
if r.mode == RESULT_STORED {

mysql.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ func (c *Client) NextResult() (more bool, err os.Error) {
332332
// Read result from server
333333
c.sequence++
334334
_, err = c.getResult(PACKET_OK | PACKET_ERROR | PACKET_RESULT)
335+
// Store fields
336+
err = c.getFields()
335337
return
336338
}
337339

statement.go

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
package mysql
77

88
import (
9+
"fmt"
910
"os"
1011
"reflect"
1112
"strconv"
12-
"fmt"
1313
)
1414

1515
// Prepared statement struct
@@ -38,6 +38,7 @@ type Statement struct {
3838
LastInsertId uint64
3939
Warnings uint16
4040
result *Result
41+
resultParams []interface{}
4142
}
4243

4344
// Prepare new statement
@@ -296,11 +297,82 @@ func (s *Statement) Execute() (err os.Error) {
296297

297298
// Bind result
298299
func (s *Statement) BindResult(params ...interface{}) (err os.Error) {
300+
s.resultParams = params
299301
return
300302
}
301303

302304
// Fetch next row
303-
func (s *Statement) Fetch() (err os.Error) {
305+
func (s *Statement) Fetch() (eof bool, err os.Error) {
306+
// Log fetch
307+
s.c.log(1, "=== Begin fetch ===")
308+
// Check result
309+
if !s.checkResult() {
310+
return false, &ClientError{CR_NO_RESULT_SET, CR_NO_RESULT_SET_STR}
311+
}
312+
var row Row
313+
// Check result mode
314+
switch s.result.mode{
315+
// Used or unused result (needs fetching)
316+
case RESULT_UNUSED, RESULT_USED:
317+
s.result.mode = RESULT_USED
318+
if s.result.allRead == true {
319+
return true, nil
320+
}
321+
eof, err := s.getRow()
322+
if err != nil {
323+
return false, err
324+
}
325+
if eof {
326+
s.result.allRead = true
327+
}
328+
row = s.result.rows[0]
329+
// Stored result
330+
case RESULT_STORED:
331+
if s.result.rowPos >= uint64(len(s.result.rows)) {
332+
return true, nil
333+
}
334+
row = s.result.rows[s.result.rowPos]
335+
s.result.rowPos ++
336+
}
337+
// Recover possible errors from type conversion
338+
defer func() {
339+
if e := recover(); e != nil {
340+
err = &ClientError{CR_UNKNOWN_ERROR, CR_UNKNOWN_ERROR_STR}
341+
}
342+
}()
343+
// Iterate bound params and assign from row (partial set quicker this way)
344+
for k, v := range s.resultParams {
345+
switch t := v.(type) {
346+
case *int:
347+
*t = int(atou64(row[k]))
348+
case *uint:
349+
*t = uint(atou64(row[k]))
350+
case *int8:
351+
*t = int8(atou64(row[k]))
352+
case *uint8:
353+
*t = uint8(atou64(row[k]))
354+
case *int16:
355+
*t = int16(atou64(row[k]))
356+
case *uint16:
357+
*t = uint16(atou64(row[k]))
358+
case *int32:
359+
*t = int32(atou64(row[k]))
360+
case *uint32:
361+
*t = uint32(atou64(row[k]))
362+
case *int64:
363+
*t = int64(atou64(row[k]))
364+
case *uint64:
365+
*t = atou64(row[k])
366+
case *float32:
367+
*t = float32(atof64(row[k]))
368+
case *float64:
369+
*t = atof64(row[k])
370+
case *[]byte:
371+
*t = row[k].([]byte)
372+
case *string:
373+
*t = atos(row[k])
374+
}
375+
}
304376
return
305377
}
306378

@@ -347,6 +419,14 @@ func (s *Statement) reset() {
347419
s.c.reset()
348420
}
349421

422+
// Check if a result exists
423+
func (s *Statement) checkResult() bool {
424+
if s.result != nil {
425+
return true
426+
}
427+
return false
428+
}
429+
350430
// Get null bit map
351431
func (s *Statement) getNullBitMap() (nbm []byte) {
352432
nbm = make([]byte, (s.paramCount+7)/8)

0 commit comments

Comments
 (0)