Example #1
0
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
}
Example #2
0
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
}
Example #3
0
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
}