func (p *Parameter) BindValue(h api.SQLHSTMT, idx int, v driver.Value) error { // TODO(brainman): Reuse memory for previously bound values. If memory // is reused, we, probably, do not need to call SQLBindParameter either. var ctype, sqltype, decimal api.SQLSMALLINT var size api.SQLULEN var buflen api.SQLLEN var plen *api.SQLLEN var buf unsafe.Pointer switch d := v.(type) { case nil: ctype = api.SQL_C_WCHAR p.Data = nil buf = nil size = 1 buflen = 0 plen = p.StoreStrLen_or_IndPtr(api.SQL_NULL_DATA) sqltype = api.SQL_WCHAR case string: ctype = api.SQL_C_WCHAR b := api.StringToUTF16(d) p.Data = b buf = unsafe.Pointer(&b[0]) l := len(b) l -= 1 // remove terminating 0 size = api.SQLULEN(l) if size < 1 { // size cannot be less then 1 even for empty fields size = 1 } l *= 2 // every char takes 2 bytes buflen = api.SQLLEN(l) plen = p.StoreStrLen_or_IndPtr(buflen) switch { case size >= 4000: sqltype = api.SQL_WLONGVARCHAR case p.isDescribed: sqltype = p.SQLType case size <= 1: sqltype = api.SQL_WVARCHAR default: sqltype = api.SQL_WCHAR } case int64: ctype = api.SQL_C_SBIGINT p.Data = &d buf = unsafe.Pointer(&d) sqltype = api.SQL_BIGINT size = 8 case bool: var b byte if d { b = 1 } ctype = api.SQL_C_BIT p.Data = &b buf = unsafe.Pointer(&b) sqltype = api.SQL_BIT size = 1 case float64: ctype = api.SQL_C_DOUBLE p.Data = &d buf = unsafe.Pointer(&d) sqltype = api.SQL_DOUBLE size = 8 case time.Time: ctype = api.SQL_C_TYPE_TIMESTAMP y, m, day := d.Date() b := api.SQL_TIMESTAMP_STRUCT{ Year: api.SQLSMALLINT(y), Month: api.SQLUSMALLINT(m), Day: api.SQLUSMALLINT(day), Hour: api.SQLUSMALLINT(d.Hour()), Minute: api.SQLUSMALLINT(d.Minute()), Second: api.SQLUSMALLINT(d.Second()), Fraction: 0, } p.Data = &b buf = unsafe.Pointer(&b) sqltype = api.SQL_TYPE_TIMESTAMP if p.isDescribed && p.SQLType == api.SQL_TYPE_TIMESTAMP { decimal = p.Decimal } if decimal <= 0 { // represented as yyyy-mm-dd hh:mm:ss.fff format in ms sql server decimal = 3 b.Fraction = api.SQLUINTEGER(d.Nanosecond() / int(time.Millisecond)) } size = 20 + api.SQLULEN(decimal) case []byte: if nil == d { ctype = api.SQL_C_WCHAR p.Data = nil buf = nil size = 1 buflen = 0 plen = p.StoreStrLen_or_IndPtr(api.SQL_NULL_DATA) sqltype = api.SQL_WCHAR } else { ctype = api.SQL_C_BINARY b := make([]byte, len(d)) copy(b, d) p.Data = b buf = unsafe.Pointer(&b[0]) buflen = api.SQLLEN(len(b)) plen = p.StoreStrLen_or_IndPtr(buflen) size = api.SQLULEN(len(b)) switch { case p.isDescribed: sqltype = p.SQLType case size <= 0: sqltype = api.SQL_LONGVARBINARY case size >= 8000: sqltype = api.SQL_LONGVARBINARY default: sqltype = api.SQL_BINARY } } default: panic(fmt.Errorf("unsupported type %T", v)) } ret := api.SQLBindParameter(h, api.SQLUSMALLINT(idx+1), api.SQL_PARAM_INPUT, ctype, sqltype, size, decimal, api.SQLPOINTER(buf), buflen, plen) if IsError(ret) { return NewError("SQLBindParameter", h) } return nil }
func (l *BufferLen) Bind(h api.SQLHSTMT, idx int, ctype api.SQLSMALLINT, buf []byte) api.SQLRETURN { return api.SQLBindCol(h, api.SQLUSMALLINT(idx+1), ctype, api.SQLPOINTER(unsafe.Pointer(&buf[0])), api.SQLLEN(len(buf)), (*api.SQLLEN)(l)) }