mirror of
1
Fork 0
forgejo/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go

197 lines
5.2 KiB
Go

// +build go1.9
package mssql
import (
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"reflect"
"time"
// "github.com/cockroachdb/apd"
"github.com/golang-sql/civil"
)
// Type alias provided for compatibility.
type MssqlDriver = Driver // Deprecated: users should transition to the new name when possible.
type MssqlBulk = Bulk // Deprecated: users should transition to the new name when possible.
type MssqlBulkOptions = BulkOptions // Deprecated: users should transition to the new name when possible.
type MssqlConn = Conn // Deprecated: users should transition to the new name when possible.
type MssqlResult = Result // Deprecated: users should transition to the new name when possible.
type MssqlRows = Rows // Deprecated: users should transition to the new name when possible.
type MssqlStmt = Stmt // Deprecated: users should transition to the new name when possible.
var _ driver.NamedValueChecker = &Conn{}
// VarChar parameter types.
type VarChar string
type NVarCharMax string
type VarCharMax string
// DateTime1 encodes parameters to original DateTime SQL types.
type DateTime1 time.Time
// DateTimeOffset encodes parameters to DateTimeOffset, preserving the UTC offset.
type DateTimeOffset time.Time
func convertInputParameter(val interface{}) (interface{}, error) {
switch v := val.(type) {
case VarChar:
return val, nil
case NVarCharMax:
return val, nil
case VarCharMax:
return val, nil
case DateTime1:
return val, nil
case DateTimeOffset:
return val, nil
case civil.Date:
return val, nil
case civil.DateTime:
return val, nil
case civil.Time:
return val, nil
// case *apd.Decimal:
// return nil
default:
return driver.DefaultParameterConverter.ConvertValue(v)
}
}
func (c *Conn) CheckNamedValue(nv *driver.NamedValue) error {
switch v := nv.Value.(type) {
case sql.Out:
if c.outs == nil {
c.outs = make(map[string]interface{})
}
c.outs[nv.Name] = v.Dest
if v.Dest == nil {
return errors.New("destination is a nil pointer")
}
dest_info := reflect.ValueOf(v.Dest)
if dest_info.Kind() != reflect.Ptr {
return errors.New("destination not a pointer")
}
if dest_info.IsNil() {
return errors.New("destination is a nil pointer")
}
pointed_value := reflect.Indirect(dest_info)
// don't allow pointer to a pointer, only pointer to a value can be handled
// correctly
if pointed_value.Kind() == reflect.Ptr {
return errors.New("destination is a pointer to a pointer")
}
// Unwrap the Out value and check the inner value.
val := pointed_value.Interface()
if val == nil {
return errors.New("MSSQL does not allow NULL value without type for OUTPUT parameters")
}
conv, err := convertInputParameter(val)
if err != nil {
return err
}
if conv == nil {
// if we replace with nil we would lose type information
nv.Value = sql.Out{Dest: val}
} else {
nv.Value = sql.Out{Dest: conv}
}
return nil
case *ReturnStatus:
*v = 0 // By default the return value should be zero.
c.returnStatus = v
return driver.ErrRemoveArgument
case TVP:
return nil
default:
var err error
nv.Value, err = convertInputParameter(nv.Value)
return err
}
}
func (s *Stmt) makeParamExtra(val driver.Value) (res param, err error) {
switch val := val.(type) {
case VarChar:
res.ti.TypeId = typeBigVarChar
res.buffer = []byte(val)
res.ti.Size = len(res.buffer)
case VarCharMax:
res.ti.TypeId = typeBigVarChar
res.buffer = []byte(val)
res.ti.Size = 0 // currently zero forces varchar(max)
case NVarCharMax:
res.ti.TypeId = typeNVarChar
res.buffer = str2ucs2(string(val))
res.ti.Size = 0 // currently zero forces nvarchar(max)
case DateTime1:
t := time.Time(val)
res.ti.TypeId = typeDateTimeN
res.buffer = encodeDateTime(t)
res.ti.Size = len(res.buffer)
case DateTimeOffset:
res.ti.TypeId = typeDateTimeOffsetN
res.ti.Scale = 7
res.buffer = encodeDateTimeOffset(time.Time(val), int(res.ti.Scale))
res.ti.Size = len(res.buffer)
case civil.Date:
res.ti.TypeId = typeDateN
res.buffer = encodeDate(val.In(time.UTC))
res.ti.Size = len(res.buffer)
case civil.DateTime:
res.ti.TypeId = typeDateTime2N
res.ti.Scale = 7
res.buffer = encodeDateTime2(val.In(time.UTC), int(res.ti.Scale))
res.ti.Size = len(res.buffer)
case civil.Time:
res.ti.TypeId = typeTimeN
res.ti.Scale = 7
res.buffer = encodeTime(val.Hour, val.Minute, val.Second, val.Nanosecond, int(res.ti.Scale))
res.ti.Size = len(res.buffer)
case sql.Out:
res, err = s.makeParam(val.Dest)
res.Flags = fByRevValue
case TVP:
err = val.check()
if err != nil {
return
}
schema, name, errGetName := getSchemeAndName(val.TypeName)
if errGetName != nil {
return
}
res.ti.UdtInfo.TypeName = name
res.ti.UdtInfo.SchemaName = schema
res.ti.TypeId = typeTvp
columnStr, tvpFieldIndexes, errCalTypes := val.columnTypes()
if errCalTypes != nil {
err = errCalTypes
return
}
res.buffer, err = val.encode(schema, name, columnStr, tvpFieldIndexes)
if err != nil {
return
}
res.ti.Size = len(res.buffer)
default:
err = fmt.Errorf("mssql: unknown type for %T", val)
}
return
}
func scanIntoOut(name string, fromServer, scanInto interface{}) error {
return convertAssign(scanInto, fromServer)
}