github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/lorry/engines/mysql/json.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package mysql 21 22 import ( 23 "database/sql" 24 "database/sql/driver" 25 "encoding/json" 26 "reflect" 27 ) 28 29 func jsonify(rows *sql.Rows) ([]byte, error) { 30 columnTypes, err := rows.ColumnTypes() 31 if err != nil { 32 return nil, err 33 } 34 var ret []interface{} 35 for rows.Next() { 36 values := prepareValues(columnTypes) 37 err := rows.Scan(values...) 38 if err != nil { 39 return nil, err 40 } 41 r, err := convert(columnTypes, values) 42 if err != nil { 43 return nil, err 44 } 45 ret = append(ret, r) 46 } 47 return json.Marshal(ret) 48 } 49 50 func prepareValues(columnTypes []*sql.ColumnType) []interface{} { 51 types := make([]reflect.Type, len(columnTypes)) 52 for i, tp := range columnTypes { 53 types[i] = tp.ScanType() 54 } 55 values := make([]interface{}, len(columnTypes)) 56 for i := range values { 57 switch types[i].Kind() { 58 case reflect.String, reflect.Interface: 59 values[i] = &sql.NullString{} 60 case reflect.Bool: 61 values[i] = &sql.NullBool{} 62 case reflect.Float64: 63 values[i] = &sql.NullFloat64{} 64 case reflect.Int16, reflect.Uint16: 65 values[i] = &sql.NullInt16{} 66 case reflect.Int32, reflect.Uint32: 67 values[i] = &sql.NullInt32{} 68 case reflect.Int64, reflect.Uint64: 69 values[i] = &sql.NullInt64{} 70 default: 71 values[i] = reflect.New(types[i]).Interface() 72 } 73 } 74 return values 75 } 76 77 func convert(columnTypes []*sql.ColumnType, values []interface{}) (map[string]interface{}, error) { 78 r := map[string]interface{}{} 79 for i, ct := range columnTypes { 80 value := values[i] 81 switch v := values[i].(type) { 82 case driver.Valuer: 83 if vv, err := v.Value(); err != nil { 84 return nil, err 85 } else { 86 value = interface{}(vv) 87 } 88 case *sql.RawBytes: 89 // special case for sql.RawBytes, see https://github.com/go-sql-driver/mysql/blob/master/fields.go#L178 90 switch ct.DatabaseTypeName() { 91 case "VARCHAR", "CHAR", "TEXT", "LONGTEXT": 92 value = string(*v) 93 } 94 } 95 if value != nil { 96 r[ct.Name()] = value 97 } 98 } 99 return r, nil 100 }