func NewColumn(h api.SQLHSTMT, idx int) (Column, error) { namebuf := make([]uint16, 150) namelen, sqltype, size, ret := describeColumn(h, idx, namebuf) if ret == api.SQL_SUCCESS_WITH_INFO && namelen > len(namebuf) { // try again with bigger buffer namebuf = make([]uint16, namelen) namelen, sqltype, size, ret = describeColumn(h, idx, namebuf) } if IsError(ret) { return nil, NewError("SQLDescribeCol", h) } if namelen > len(namebuf) { // still complaining about buffer size return nil, errors.New("Failed to allocate column name buffer") } b := &BaseColumn{ name: api.UTF16ToString(namebuf[:namelen]), } switch sqltype { case api.SQL_BIT: return NewBindableColumn(b, api.SQL_C_BIT, 1), nil case api.SQL_TINYINT, api.SQL_SMALLINT, api.SQL_INTEGER: return NewBindableColumn(b, api.SQL_C_LONG, 4), nil case api.SQL_BIGINT: return NewBindableColumn(b, api.SQL_C_SBIGINT, 8), nil case api.SQL_NUMERIC, api.SQL_DECIMAL, api.SQL_FLOAT, api.SQL_REAL, api.SQL_DOUBLE: return NewBindableColumn(b, api.SQL_C_DOUBLE, 8), nil case api.SQL_TYPE_TIME: var v api.SQL_TIMESTAMP_STRUCT return NewBindableColumn(b, api.SQL_C_TYPE_TIMESTAMP, int(unsafe.Sizeof(v))), nil case api.SQL_TYPE_TIMESTAMP: var v api.SQL_TIMESTAMP_STRUCT return NewBindableColumn(b, api.SQL_C_TYPE_TIMESTAMP, int(unsafe.Sizeof(v))), nil case api.SQL_TYPE_DATE: var v api.SQL_DATE_STRUCT return NewBindableColumn(b, api.SQL_C_DATE, int(unsafe.Sizeof(v))), nil case api.SQL_GUID: var v api.SQLGUID return NewBindableColumn(b, api.SQL_C_GUID, int(unsafe.Sizeof(v))), nil case api.SQL_CHAR, api.SQL_VARCHAR: return NewVariableWidthColumn(b, api.SQL_C_CHAR, size) case api.SQL_WCHAR, api.SQL_WVARCHAR: return NewVariableWidthColumn(b, api.SQL_C_WCHAR, size) case api.SQL_BINARY, api.SQL_VARBINARY: return NewVariableWidthColumn(b, api.SQL_C_BINARY, size) case api.SQL_LONGVARCHAR: return NewVariableWidthColumn(b, api.SQL_C_CHAR, 0) case api.SQL_WLONGVARCHAR, api.SQL_SS_XML: return NewVariableWidthColumn(b, api.SQL_C_WCHAR, 0) case api.SQL_LONGVARBINARY: return NewVariableWidthColumn(b, api.SQL_C_BINARY, 0) } return nil, fmt.Errorf("unsupported column type %d", sqltype) }
func NewError(apiName string, handle interface{}) (err error) { // catch any panics -- possible with calls the api with invalid handles defer func() { if r := recover(); r != nil { err = fmt.Errorf("%#v", r) } }() h, ht := ToHandleAndType(handle) e := &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) { return 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 } e.Diag = append(e.Diag, r) } return e }
// https://github.com/alexbrainman/odbc/issues/27 func TestMSSQLUTF16ToUTF8(t *testing.T) { s := []uint16{0x47, 0x75, 0x73, 0x74, 0x61, 0x66, 0x27, 0x73, 0x20, 0x4b, 0x6e, 0xe4, 0x63, 0x6b, 0x65, 0x62, 0x72, 0xf6, 0x64} if api.UTF16ToString(s) != string(utf16toutf8(s)) { t.Fatal("comparison fails") } }