mirror of
https://github.com/documize/community.git
synced 2025-07-27 17:19:42 +02:00
Microsoft SQL Server driver and prep
This commit is contained in:
parent
e6335dd58c
commit
deb579d8ad
63 changed files with 73767 additions and 13 deletions
167
vendor/github.com/denisenkom/go-mssqldb/tvp_go19.go
generated
vendored
Normal file
167
vendor/github.com/denisenkom/go-mssqldb/tvp_go19.go
generated
vendored
Normal file
|
@ -0,0 +1,167 @@
|
|||
// +build go1.9
|
||||
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorEmptyTVPName = errors.New("TVPTypeName must not be empty")
|
||||
ErrorTVPTypeSlice = errors.New("TVPType must be slice type")
|
||||
ErrorTVPTypeSliceIsEmpty = errors.New("TVPType mustn't be null value")
|
||||
)
|
||||
|
||||
//TVPType is driver type, which allows supporting Table Valued Parameters (TVP) in SQL Server
|
||||
type TVPType struct {
|
||||
//TVP param name, mustn't be default value
|
||||
TVPTypeName string
|
||||
//TVP scheme name
|
||||
TVPScheme string
|
||||
//TVP Value. Param must be the slice, mustn't be nil
|
||||
TVPValue interface{}
|
||||
}
|
||||
|
||||
func (tvp TVPType) check() error {
|
||||
if len(tvp.TVPTypeName) == 0 {
|
||||
return ErrorEmptyTVPName
|
||||
}
|
||||
valueOf := reflect.ValueOf(tvp.TVPValue)
|
||||
if valueOf.Kind() != reflect.Slice {
|
||||
return ErrorTVPTypeSlice
|
||||
}
|
||||
if valueOf.IsNil() {
|
||||
return ErrorTVPTypeSliceIsEmpty
|
||||
}
|
||||
if reflect.TypeOf(tvp.TVPValue).Elem().Kind() != reflect.Struct {
|
||||
return ErrorTVPTypeSlice
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tvp TVPType) encode() ([]byte, error) {
|
||||
columnStr, err := tvp.columnTypes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
preparedBuffer := make([]byte, 0, 20+(10*len(columnStr)))
|
||||
buf := bytes.NewBuffer(preparedBuffer)
|
||||
err = writeBVarChar(buf, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeBVarChar(buf, tvp.TVPScheme)
|
||||
writeBVarChar(buf, tvp.TVPTypeName)
|
||||
|
||||
binary.Write(buf, binary.LittleEndian, uint16(len(columnStr)))
|
||||
|
||||
for i, column := range columnStr {
|
||||
binary.Write(buf, binary.LittleEndian, uint32(column.UserType))
|
||||
binary.Write(buf, binary.LittleEndian, uint16(column.Flags))
|
||||
writeTypeInfo(buf, &columnStr[i].ti)
|
||||
writeBVarChar(buf, "")
|
||||
}
|
||||
buf.WriteByte(_TVP_END_TOKEN)
|
||||
conn := new(Conn)
|
||||
conn.sess = new(tdsSession)
|
||||
conn.sess.loginAck = loginAckStruct{TDSVersion: verTDS73}
|
||||
stmt := &Stmt{
|
||||
c: conn,
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(tvp.TVPValue)
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
refStr := reflect.ValueOf(val.Index(i).Interface())
|
||||
buf.WriteByte(_TVP_ROW_TOKEN)
|
||||
for j := 0; j < refStr.NumField(); j++ {
|
||||
field := refStr.Field(j)
|
||||
tvpVal := field.Interface()
|
||||
valOf := reflect.ValueOf(tvpVal)
|
||||
elemKind := field.Kind()
|
||||
if elemKind == reflect.Ptr && valOf.IsNil() {
|
||||
switch tvpVal.(type) {
|
||||
case *bool, *time.Time, *int8, *int16, *int32, *int64, *float32, *float64:
|
||||
binary.Write(buf, binary.LittleEndian, uint8(0))
|
||||
continue
|
||||
default:
|
||||
binary.Write(buf, binary.LittleEndian, uint64(_PLP_NULL))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if elemKind == reflect.Slice && valOf.IsNil() {
|
||||
binary.Write(buf, binary.LittleEndian, uint64(_PLP_NULL))
|
||||
continue
|
||||
}
|
||||
|
||||
cval, err := convertInputParameter(tvpVal)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert tvp parameter row col: %s", err)
|
||||
}
|
||||
param, err := stmt.makeParam(cval)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to make tvp parameter row col: %s", err)
|
||||
}
|
||||
columnStr[j].ti.Writer(buf, param.ti, param.buffer)
|
||||
}
|
||||
}
|
||||
buf.WriteByte(_TVP_END_TOKEN)
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (tvp TVPType) columnTypes() ([]columnStruct, error) {
|
||||
val := reflect.ValueOf(tvp.TVPValue)
|
||||
var firstRow interface{}
|
||||
if val.Len() != 0 {
|
||||
firstRow = val.Index(0).Interface()
|
||||
} else {
|
||||
firstRow = reflect.New(reflect.TypeOf(tvp.TVPValue).Elem()).Elem().Interface()
|
||||
}
|
||||
|
||||
tvpRow := reflect.TypeOf(firstRow)
|
||||
columnCount := tvpRow.NumField()
|
||||
defaultValues := make([]interface{}, 0, columnCount)
|
||||
|
||||
for i := 0; i < columnCount; i++ {
|
||||
typeField := tvpRow.Field(i).Type
|
||||
if typeField.Kind() == reflect.Ptr {
|
||||
v := reflect.New(typeField.Elem())
|
||||
defaultValues = append(defaultValues, v.Interface())
|
||||
continue
|
||||
}
|
||||
defaultValues = append(defaultValues, reflect.Zero(typeField).Interface())
|
||||
}
|
||||
|
||||
conn := new(Conn)
|
||||
conn.sess = new(tdsSession)
|
||||
conn.sess.loginAck = loginAckStruct{TDSVersion: verTDS73}
|
||||
stmt := &Stmt{
|
||||
c: conn,
|
||||
}
|
||||
|
||||
columnConfiguration := make([]columnStruct, 0, columnCount)
|
||||
for index, val := range defaultValues {
|
||||
cval, err := convertInputParameter(val)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert tvp parameter row %d col %d: %s", index, val, err)
|
||||
}
|
||||
param, err := stmt.makeParam(cval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
column := columnStruct{
|
||||
ti: param.ti,
|
||||
}
|
||||
switch param.ti.TypeId {
|
||||
case typeNVarChar, typeBigVarBin:
|
||||
column.ti.Size = 0
|
||||
}
|
||||
columnConfiguration = append(columnConfiguration, column)
|
||||
}
|
||||
|
||||
return columnConfiguration, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue