github.com/dolthub/go-mysql-server@v0.18.0/driver/rows.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package driver 16 17 import ( 18 "database/sql/driver" 19 "reflect" 20 21 "github.com/dolthub/vitess/go/vt/proto/query" 22 23 "github.com/dolthub/go-mysql-server/sql" 24 "github.com/dolthub/go-mysql-server/sql/types" 25 ) 26 27 // Rows is an iterator over an executed query's results. 28 type Rows struct { 29 options *Options 30 ctx *sql.Context 31 cols sql.Schema 32 rows sql.RowIter 33 } 34 35 // Columns returns the names of the columns. The number of 36 // columns of the result is inferred from the length of the 37 // slice. If a particular column name isn't known, an empty 38 // string should be returned for that entry. 39 func (r *Rows) Columns() []string { 40 names := make([]string, len(r.cols)) 41 for i, col := range r.cols { 42 names[i] = col.Name 43 } 44 return names 45 } 46 47 // Close closes the rows iterator. 48 func (r *Rows) Close() error { 49 return r.rows.Close(r.ctx) 50 } 51 52 // Next is called to populate the next row of data into 53 // the provided slice. The provided slice will be the same 54 // size as the Columns() are wide. 55 // 56 // Next should return io.EOF when there are no more rows. 57 // 58 // The dest should not be written to outside of Next. Care 59 // should be taken when closing Rows not to modify 60 // a buffer held in dest. 61 func (r *Rows) Next(dest []driver.Value) error { 62 again: 63 row, err := r.rows.Next(r.ctx) 64 if err != nil { 65 return err 66 } 67 if len(row) == 0 { 68 return nil 69 } 70 71 if _, ok := row[0].(types.OkResult); ok { 72 // skip OK results 73 goto again 74 } 75 76 for i := range row { 77 dest[i] = r.convert(i, row[i]) 78 } 79 return nil 80 } 81 82 func (r *Rows) convert(col int, v driver.Value) interface{} { 83 switch r.cols[col].Type.Type() { 84 case query.Type_NULL_TYPE: 85 return nil 86 87 case query.Type_INT8, query.Type_INT16, query.Type_INT24, query.Type_INT32, query.Type_INT64, 88 query.Type_UINT8, query.Type_UINT16, query.Type_UINT24, query.Type_UINT32, query.Type_UINT64, 89 query.Type_FLOAT32, query.Type_FLOAT64: 90 rv := reflect.ValueOf(v) 91 switch rv.Kind() { 92 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 93 return rv.Int() 94 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 95 return rv.Uint() 96 case reflect.Float32, reflect.Float64: 97 return rv.Float() 98 case reflect.String: 99 return rv.String() 100 } 101 102 case query.Type_JSON: 103 var asObj, asStr bool 104 if r.options != nil { 105 switch r.options.JSON { 106 case ScanAsObject: 107 asObj = true 108 case ScanAsString: 109 asStr = true 110 case ScanAsBytes: 111 // nothing to do 112 default: // unknown or ScanAsStored 113 return v 114 } 115 } 116 117 sqlValue, _, err := r.cols[col].Type.Convert(v) 118 if err != nil { 119 break 120 } 121 doc, ok := sqlValue.(types.JSONDocument) 122 if !ok { 123 break 124 } 125 if asObj { 126 return doc.Val 127 } 128 129 str, err := doc.JSONString() 130 if err != nil { 131 break 132 } 133 134 if asStr { 135 return str 136 } 137 return []byte(str) 138 } 139 return v 140 }