func NewError(apiName string, handle interface{}) error { h, ht := ToHandleAndType(handle) err := &Error{APIName: apiName} var ne api.SQLINTEGER state := make([]uint16, 6) msg := make([]uint16, api.SQL_MAX_MESSAGE_LENGTH) for i := 1; ; i++ { ret := api.SQLGetDiagRec(ht, h, api.SQLSMALLINT(i), (*api.SQLWCHAR)(unsafe.Pointer(&state[0])), &ne, (*api.SQLWCHAR)(unsafe.Pointer(&msg[0])), api.SQLSMALLINT(len(msg)), nil) if ret == api.SQL_NO_DATA { break } if IsError(ret) { panic(fmt.Errorf("SQLGetDiagRec failed: ret=%d", ret)) } r := DiagRecord{ State: api.UTF16ToString(state), NativeError: int(ne), Message: api.UTF16ToString(msg), } if r.State == "08S01" { return driver.ErrBadConn } err.Diag = append(err.Diag, r) } return err }
func describeColumn(h api.SQLHSTMT, idx int, namebuf []uint16) (namelen int, sqltype api.SQLSMALLINT, size api.SQLULEN, ret api.SQLRETURN) { var l, decimal, nullable api.SQLSMALLINT ret = api.SQLDescribeCol(h, api.SQLUSMALLINT(idx+1), (*api.SQLWCHAR)(unsafe.Pointer(&namebuf[0])), api.SQLSMALLINT(len(namebuf)), &l, &sqltype, &size, &decimal, &nullable) return int(l), sqltype, size, ret }
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: api.SQLUINTEGER(d.Nanosecond()), } 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 } size = 20 + api.SQLULEN(decimal) case []byte: 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 }