binding.go 2.9 KB
Newer Older
martianzhang's avatar
martianzhang 已提交
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
package native

import (
	"github.com/ziutek/mymysql/mysql"
	"reflect"
	"time"
)

var (
	timeType      = reflect.TypeOf(time.Time{})
	timestampType = reflect.TypeOf(mysql.Timestamp{})
	dateType      = reflect.TypeOf(mysql.Date{})
	durationType  = reflect.TypeOf(time.Duration(0))
	blobType      = reflect.TypeOf(mysql.Blob{})
	rawType       = reflect.TypeOf(mysql.Raw{})
)

// val should be an addressable value
func bindValue(val reflect.Value) (out paramValue) {
	if !val.IsValid() {
		out.typ = MYSQL_TYPE_NULL
		return
	}
	typ := val.Type()
	if typ.Kind() == reflect.Ptr {
		// We have addressable pointer
		out.addr = val.Addr()
		// Dereference pointer for next operation on its value
		typ = typ.Elem()
		val = val.Elem()
	} else {
		// We have addressable value. Create a pointer to it
		pv := val.Addr()
		// This pointer is unaddressable so copy it and return an address
		out.addr = reflect.New(pv.Type())
		out.addr.Elem().Set(pv)
	}

	// Obtain value type
	switch typ.Kind() {
	case reflect.String:
		out.typ = MYSQL_TYPE_STRING
		out.length = -1
		return

	case reflect.Int:
		out.typ = _INT_TYPE
		out.length = _SIZE_OF_INT
		return

	case reflect.Int8:
		out.typ = MYSQL_TYPE_TINY
		out.length = 1
		return

	case reflect.Int16:
		out.typ = MYSQL_TYPE_SHORT
		out.length = 2
		return

	case reflect.Int32:
		out.typ = MYSQL_TYPE_LONG
		out.length = 4
		return

	case reflect.Int64:
		if typ == durationType {
			out.typ = MYSQL_TYPE_TIME
			out.length = -1
			return
		}
		out.typ = MYSQL_TYPE_LONGLONG
		out.length = 8
		return

	case reflect.Uint:
		out.typ = _INT_TYPE | MYSQL_UNSIGNED_MASK
		out.length = _SIZE_OF_INT
		return

	case reflect.Uint8:
		out.typ = MYSQL_TYPE_TINY | MYSQL_UNSIGNED_MASK
		out.length = 1
		return

	case reflect.Uint16:
		out.typ = MYSQL_TYPE_SHORT | MYSQL_UNSIGNED_MASK
		out.length = 2
		return

	case reflect.Uint32:
		out.typ = MYSQL_TYPE_LONG | MYSQL_UNSIGNED_MASK
		out.length = 4
		return

	case reflect.Uint64:
		out.typ = MYSQL_TYPE_LONGLONG | MYSQL_UNSIGNED_MASK
		out.length = 8
		return

	case reflect.Float32:
		out.typ = MYSQL_TYPE_FLOAT
		out.length = 4
		return

	case reflect.Float64:
		out.typ = MYSQL_TYPE_DOUBLE
		out.length = 8
		return

	case reflect.Slice:
		out.length = -1
		if typ == blobType {
			out.typ = MYSQL_TYPE_BLOB
			return
		}
		if typ.Elem().Kind() == reflect.Uint8 {
			out.typ = MYSQL_TYPE_VAR_STRING
			return
		}

	case reflect.Struct:
		out.length = -1
		if typ == timeType {
			out.typ = MYSQL_TYPE_DATETIME
			return
		}
		if typ == dateType {
			out.typ = MYSQL_TYPE_DATE
			return
		}
		if typ == timestampType {
			out.typ = MYSQL_TYPE_TIMESTAMP
			return
		}
		if typ == rawType {
			out.typ = val.FieldByName("Typ").Interface().(uint16)
			out.addr = val.FieldByName("Val").Addr()
			out.raw = true
			return
		}

	case reflect.Bool:
		out.typ = MYSQL_TYPE_TINY
		// bool implementation isn't documented so we treat it in special way
		out.length = -1
		return
	}
	panic(mysql.ErrBindUnkType)
}