gitea/vendor/github.com/denisenkom/go-mssqldb/types.go

846 lines
20 KiB
Go

package mssql
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
"time"
)
// fixed-length data types
// http://msdn.microsoft.com/en-us/library/dd341171.aspx
const (
typeNull = 0x1f
typeInt1 = 0x30
typeBit = 0x32
typeInt2 = 0x34
typeInt4 = 0x38
typeDateTim4 = 0x3a
typeFlt4 = 0x3b
typeMoney = 0x3c
typeDateTime = 0x3d
typeFlt8 = 0x3e
typeMoney4 = 0x7a
typeInt8 = 0x7f
)
// variable-length data types
// http://msdn.microsoft.com/en-us/library/dd358341.aspx
const (
// byte len types
typeGuid = 0x24
typeIntN = 0x26
typeDecimal = 0x37 // legacy
typeNumeric = 0x3f // legacy
typeBitN = 0x68
typeDecimalN = 0x6a
typeNumericN = 0x6c
typeFltN = 0x6d
typeMoneyN = 0x6e
typeDateTimeN = 0x6f
typeDateN = 0x28
typeTimeN = 0x29
typeDateTime2N = 0x2a
typeDateTimeOffsetN = 0x2b
typeChar = 0x2f // legacy
typeVarChar = 0x27 // legacy
typeBinary = 0x2d // legacy
typeVarBinary = 0x25 // legacy
// short length types
typeBigVarBin = 0xa5
typeBigVarChar = 0xa7
typeBigBinary = 0xad
typeBigChar = 0xaf
typeNVarChar = 0xe7
typeNChar = 0xef
typeXml = 0xf1
typeUdt = 0xf0
// long length types
typeText = 0x23
typeImage = 0x22
typeNText = 0x63
typeVariant = 0x62
)
// TYPE_INFO rule
// http://msdn.microsoft.com/en-us/library/dd358284.aspx
type typeInfo struct {
TypeId uint8
Size int
Scale uint8
Prec uint8
Buffer []byte
Collation collation
Reader func(ti *typeInfo, r *tdsBuffer) (res interface{})
Writer func(w io.Writer, ti typeInfo, buf []byte) (err error)
}
func readTypeInfo(r *tdsBuffer) (res typeInfo) {
res.TypeId = r.byte()
switch res.TypeId {
case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4,
typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8:
// those are fixed length types
switch res.TypeId {
case typeNull:
res.Size = 0
case typeInt1, typeBit:
res.Size = 1
case typeInt2:
res.Size = 2
case typeInt4, typeDateTim4, typeFlt4, typeMoney4:
res.Size = 4
case typeMoney, typeDateTime, typeFlt8, typeInt8:
res.Size = 8
}
res.Reader = readFixedType
res.Buffer = make([]byte, res.Size)
default: // all others are VARLENTYPE
readVarLen(&res, r)
}
return
}
func writeTypeInfo(w io.Writer, ti *typeInfo) (err error) {
err = binary.Write(w, binary.LittleEndian, ti.TypeId)
if err != nil {
return
}
switch ti.TypeId {
case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4,
typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8:
// those are fixed length types
default: // all others are VARLENTYPE
err = writeVarLen(w, ti)
if err != nil {
return
}
}
return
}
func writeVarLen(w io.Writer, ti *typeInfo) (err error) {
switch ti.TypeId {
case typeDateN:
case typeTimeN, typeDateTime2N, typeDateTimeOffsetN:
if err = binary.Write(w, binary.LittleEndian, ti.Scale); err != nil {
return
}
ti.Writer = writeByteLenType
case typeGuid, typeIntN, typeDecimal, typeNumeric,
typeBitN, typeDecimalN, typeNumericN, typeFltN,
typeMoneyN, typeDateTimeN, typeChar,
typeVarChar, typeBinary, typeVarBinary:
// byle len types
if ti.Size > 0xff {
panic("Invalid size for BYLELEN_TYPE")
}
if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil {
return
}
switch ti.TypeId {
case typeDecimal, typeNumeric, typeDecimalN, typeNumericN:
err = binary.Write(w, binary.LittleEndian, ti.Prec)
if err != nil {
return
}
err = binary.Write(w, binary.LittleEndian, ti.Scale)
if err != nil {
return
}
}
ti.Writer = writeByteLenType
case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar,
typeNVarChar, typeNChar, typeXml, typeUdt:
// short len types
if ti.Size > 8000 || ti.Size == 0 {
if err = binary.Write(w, binary.LittleEndian, uint16(0xffff)); err != nil {
return
}
ti.Writer = writePLPType
} else {
if err = binary.Write(w, binary.LittleEndian, uint16(ti.Size)); err != nil {
return
}
ti.Writer = writeShortLenType
}
switch ti.TypeId {
case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar:
if err = writeCollation(w, ti.Collation); err != nil {
return
}
case typeXml:
var schemapresent uint8 = 0
if err = binary.Write(w, binary.LittleEndian, schemapresent); err != nil {
return
}
}
case typeText, typeImage, typeNText, typeVariant:
// LONGLEN_TYPE
panic("LONGLEN_TYPE not implemented")
default:
panic("Invalid type")
}
return
}
// http://msdn.microsoft.com/en-us/library/ee780895.aspx
func decodeDateTim4(buf []byte) time.Time {
days := binary.LittleEndian.Uint16(buf)
mins := binary.LittleEndian.Uint16(buf[2:])
return time.Date(1900, 1, 1+int(days),
0, int(mins), 0, 0, time.UTC)
}
func decodeDateTime(buf []byte) time.Time {
days := int32(binary.LittleEndian.Uint32(buf))
tm := binary.LittleEndian.Uint32(buf[4:])
ns := int(math.Trunc(float64(tm%300)/0.3+0.5)) * 1000000
secs := int(tm / 300)
return time.Date(1900, 1, 1+int(days),
0, 0, secs, ns, time.UTC)
}
func readFixedType(ti *typeInfo, r *tdsBuffer) (res interface{}) {
r.ReadFull(ti.Buffer)
buf := ti.Buffer
switch ti.TypeId {
case typeNull:
return nil
case typeInt1:
return int64(buf[0])
case typeBit:
return buf[0] != 0
case typeInt2:
return int64(int16(binary.LittleEndian.Uint16(buf)))
case typeInt4:
return int64(int32(binary.LittleEndian.Uint32(buf)))
case typeDateTim4:
return decodeDateTim4(buf)
case typeFlt4:
return math.Float32frombits(binary.LittleEndian.Uint32(buf))
case typeMoney4:
return decodeMoney4(buf)
case typeMoney:
return decodeMoney(buf)
case typeDateTime:
return decodeDateTime(buf)
case typeFlt8:
return math.Float64frombits(binary.LittleEndian.Uint64(buf))
case typeInt8:
return int64(binary.LittleEndian.Uint64(buf))
default:
badStreamPanicf("Invalid typeid")
}
panic("shoulnd't get here")
}
func writeFixedType(w io.Writer, ti typeInfo, buf []byte) (err error) {
_, err = w.Write(buf)
return
}
func readByteLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) {
size := r.byte()
if size == 0 {
return nil
}
r.ReadFull(ti.Buffer[:size])
buf := ti.Buffer[:size]
switch ti.TypeId {
case typeDateN:
if len(buf) != 3 {
badStreamPanicf("Invalid size for DATENTYPE")
}
return decodeDate(buf)
case typeTimeN:
return decodeTime(ti.Scale, buf)
case typeDateTime2N:
return decodeDateTime2(ti.Scale, buf)
case typeDateTimeOffsetN:
return decodeDateTimeOffset(ti.Scale, buf)
case typeGuid:
return decodeGuid(buf)
case typeIntN:
switch len(buf) {
case 1:
return int64(buf[0])
case 2:
return int64(int16((binary.LittleEndian.Uint16(buf))))
case 4:
return int64(int32(binary.LittleEndian.Uint32(buf)))
case 8:
return int64(binary.LittleEndian.Uint64(buf))
default:
badStreamPanicf("Invalid size for INTNTYPE")
}
case typeDecimal, typeNumeric, typeDecimalN, typeNumericN:
return decodeDecimal(ti.Prec, ti.Scale, buf)
case typeBitN:
if len(buf) != 1 {
badStreamPanicf("Invalid size for BITNTYPE")
}
return buf[0] != 0
case typeFltN:
switch len(buf) {
case 4:
return float64(math.Float32frombits(binary.LittleEndian.Uint32(buf)))
case 8:
return math.Float64frombits(binary.LittleEndian.Uint64(buf))
default:
badStreamPanicf("Invalid size for FLTNTYPE")
}
case typeMoneyN:
switch len(buf) {
case 4:
return decodeMoney4(buf)
case 8:
return decodeMoney(buf)
default:
badStreamPanicf("Invalid size for MONEYNTYPE")
}
case typeDateTimeN:
switch len(buf) {
case 4:
return decodeDateTim4(buf)
case 8:
return decodeDateTime(buf)
default:
badStreamPanicf("Invalid size for DATETIMENTYPE")
}
case typeChar, typeVarChar:
return decodeChar(ti.Collation, buf)
case typeBinary, typeVarBinary:
// a copy, because the backing array for ti.Buffer is reused
// and can be overwritten by the next row while this row waits
// in a buffered chan
cpy := make([]byte, len(buf))
copy(cpy, buf)
return cpy
default:
badStreamPanicf("Invalid typeid")
}
panic("shoulnd't get here")
}
func writeByteLenType(w io.Writer, ti typeInfo, buf []byte) (err error) {
if ti.Size > 0xff {
panic("Invalid size for BYTELEN_TYPE")
}
err = binary.Write(w, binary.LittleEndian, uint8(ti.Size))
if err != nil {
return
}
_, err = w.Write(buf)
return
}
func readShortLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) {
size := r.uint16()
if size == 0xffff {
return nil
}
r.ReadFull(ti.Buffer[:size])
buf := ti.Buffer[:size]
switch ti.TypeId {
case typeBigVarChar, typeBigChar:
return decodeChar(ti.Collation, buf)
case typeBigVarBin, typeBigBinary:
// a copy, because the backing array for ti.Buffer is reused
// and can be overwritten by the next row while this row waits
// in a buffered chan
cpy := make([]byte, len(buf))
copy(cpy, buf)
return cpy
case typeNVarChar, typeNChar:
return decodeNChar(buf)
case typeUdt:
return decodeUdt(*ti, buf)
default:
badStreamPanicf("Invalid typeid")
}
panic("shoulnd't get here")
}
func writeShortLenType(w io.Writer, ti typeInfo, buf []byte) (err error) {
if buf == nil {
err = binary.Write(w, binary.LittleEndian, uint16(0xffff))
return
}
if ti.Size > 0xfffe {
panic("Invalid size for USHORTLEN_TYPE")
}
err = binary.Write(w, binary.LittleEndian, uint16(ti.Size))
if err != nil {
return
}
_, err = w.Write(buf)
return
}
func readLongLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) {
// information about this format can be found here:
// http://msdn.microsoft.com/en-us/library/dd304783.aspx
// and here:
// http://msdn.microsoft.com/en-us/library/dd357254.aspx
textptrsize := int(r.byte())
if textptrsize == 0 {
return nil
}
textptr := make([]byte, textptrsize)
r.ReadFull(textptr)
timestamp := r.uint64()
_ = timestamp // ignore timestamp
size := r.int32()
if size == -1 {
return nil
}
buf := make([]byte, size)
r.ReadFull(buf)
switch ti.TypeId {
case typeText:
return decodeChar(ti.Collation, buf)
case typeImage:
return buf
case typeNText:
return decodeNChar(buf)
default:
badStreamPanicf("Invalid typeid")
}
panic("shoulnd't get here")
}
// reads variant value
// http://msdn.microsoft.com/en-us/library/dd303302.aspx
func readVariantType(ti *typeInfo, r *tdsBuffer) (res interface{}) {
size := r.int32()
if size == 0 {
return nil
}
vartype := r.byte()
propbytes := int32(r.byte())
switch vartype {
case typeGuid:
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return buf
case typeBit:
return r.byte() != 0
case typeInt1:
return int64(r.byte())
case typeInt2:
return int64(int16(r.uint16()))
case typeInt4:
return int64(r.int32())
case typeInt8:
return int64(r.uint64())
case typeDateTime:
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeDateTime(buf)
case typeDateTim4:
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeDateTim4(buf)
case typeFlt4:
return float64(math.Float32frombits(r.uint32()))
case typeFlt8:
return math.Float64frombits(r.uint64())
case typeMoney4:
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeMoney4(buf)
case typeMoney:
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeMoney(buf)
case typeDateN:
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeDate(buf)
case typeTimeN:
scale := r.byte()
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeTime(scale, buf)
case typeDateTime2N:
scale := r.byte()
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeDateTime2(scale, buf)
case typeDateTimeOffsetN:
scale := r.byte()
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeDateTimeOffset(scale, buf)
case typeBigVarBin, typeBigBinary:
r.uint16() // max length, ignoring
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return buf
case typeDecimalN, typeNumericN:
prec := r.byte()
scale := r.byte()
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeDecimal(prec, scale, buf)
case typeBigVarChar, typeBigChar:
col := readCollation(r)
r.uint16() // max length, ignoring
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeChar(col, buf)
case typeNVarChar, typeNChar:
_ = readCollation(r)
r.uint16() // max length, ignoring
buf := make([]byte, size-2-propbytes)
r.ReadFull(buf)
return decodeNChar(buf)
default:
badStreamPanicf("Invalid variant typeid")
}
panic("shoulnd't get here")
}
// partially length prefixed stream
// http://msdn.microsoft.com/en-us/library/dd340469.aspx
func readPLPType(ti *typeInfo, r *tdsBuffer) (res interface{}) {
size := r.uint64()
var buf *bytes.Buffer
switch size {
case 0xffffffffffffffff:
// null
return nil
case 0xfffffffffffffffe:
// size unknown
buf = bytes.NewBuffer(make([]byte, 0, 1000))
default:
buf = bytes.NewBuffer(make([]byte, 0, size))
}
for true {
chunksize := r.uint32()
if chunksize == 0 {
break
}
if _, err := io.CopyN(buf, r, int64(chunksize)); err != nil {
badStreamPanicf("Reading PLP type failed: %s", err.Error())
}
}
switch ti.TypeId {
case typeXml:
return decodeXml(*ti, buf.Bytes())
case typeBigVarChar, typeBigChar, typeText:
return decodeChar(ti.Collation, buf.Bytes())
case typeBigVarBin, typeBigBinary, typeImage:
return buf.Bytes()
case typeNVarChar, typeNChar, typeNText:
return decodeNChar(buf.Bytes())
case typeUdt:
return decodeUdt(*ti, buf.Bytes())
}
panic("shoulnd't get here")
}
func writePLPType(w io.Writer, ti typeInfo, buf []byte) (err error) {
if err = binary.Write(w, binary.LittleEndian, uint64(len(buf))); err != nil {
return
}
for {
chunksize := uint32(len(buf))
if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil {
return
}
if chunksize == 0 {
return
}
if _, err = w.Write(buf[:chunksize]); err != nil {
return
}
buf = buf[chunksize:]
}
}
func readVarLen(ti *typeInfo, r *tdsBuffer) {
switch ti.TypeId {
case typeDateN:
ti.Size = 3
ti.Reader = readByteLenType
ti.Buffer = make([]byte, ti.Size)
case typeTimeN, typeDateTime2N, typeDateTimeOffsetN:
ti.Scale = r.byte()
switch ti.Scale {
case 0, 1, 2:
ti.Size = 3
case 3, 4:
ti.Size = 4
case 5, 6, 7:
ti.Size = 5
default:
badStreamPanicf("Invalid scale for TIME/DATETIME2/DATETIMEOFFSET type")
}
switch ti.TypeId {
case typeDateTime2N:
ti.Size += 3
case typeDateTimeOffsetN:
ti.Size += 5
}
ti.Reader = readByteLenType
ti.Buffer = make([]byte, ti.Size)
case typeGuid, typeIntN, typeDecimal, typeNumeric,
typeBitN, typeDecimalN, typeNumericN, typeFltN,
typeMoneyN, typeDateTimeN, typeChar,
typeVarChar, typeBinary, typeVarBinary:
// byle len types
ti.Size = int(r.byte())
ti.Buffer = make([]byte, ti.Size)
switch ti.TypeId {
case typeDecimal, typeNumeric, typeDecimalN, typeNumericN:
ti.Prec = r.byte()
ti.Scale = r.byte()
}
ti.Reader = readByteLenType
case typeXml:
schemapresent := r.byte()
if schemapresent != 0 {
// just ignore this for now
// dbname
r.BVarChar()
// owning schema
r.BVarChar()
// xml schema collection
r.UsVarChar()
}
ti.Reader = readPLPType
case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar,
typeNVarChar, typeNChar, typeUdt:
// short len types
ti.Size = int(r.uint16())
switch ti.TypeId {
case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar:
ti.Collation = readCollation(r)
}
if ti.Size == 0xffff {
ti.Reader = readPLPType
} else {
ti.Buffer = make([]byte, ti.Size)
ti.Reader = readShortLenType
}
case typeText, typeImage, typeNText, typeVariant:
// LONGLEN_TYPE
ti.Size = int(r.int32())
switch ti.TypeId {
case typeText, typeNText:
ti.Collation = readCollation(r)
// ignore tablenames
numparts := int(r.byte())
for i := 0; i < numparts; i++ {
r.UsVarChar()
}
ti.Reader = readLongLenType
case typeImage:
// ignore tablenames
numparts := int(r.byte())
for i := 0; i < numparts; i++ {
r.UsVarChar()
}
ti.Reader = readLongLenType
case typeVariant:
ti.Reader = readVariantType
}
default:
badStreamPanicf("Invalid type %d", ti.TypeId)
}
return
}
func decodeMoney(buf []byte) []byte {
money := int64(uint64(buf[4]) |
uint64(buf[5])<<8 |
uint64(buf[6])<<16 |
uint64(buf[7])<<24 |
uint64(buf[0])<<32 |
uint64(buf[1])<<40 |
uint64(buf[2])<<48 |
uint64(buf[3])<<56)
return scaleBytes(strconv.FormatInt(money, 10), 4)
}
func decodeMoney4(buf []byte) []byte {
money := int32(binary.LittleEndian.Uint32(buf[0:4]))
return scaleBytes(strconv.FormatInt(int64(money), 10), 4)
}
func decodeGuid(buf []byte) []byte {
res := make([]byte, 16)
copy(res, buf)
return res
}
func decodeDecimal(prec uint8, scale uint8, buf []byte) []byte {
var sign uint8
sign = buf[0]
dec := Decimal{
positive: sign != 0,
prec: prec,
scale: scale,
}
buf = buf[1:]
l := len(buf) / 4
for i := 0; i < l; i++ {
dec.integer[i] = binary.LittleEndian.Uint32(buf[0:4])
buf = buf[4:]
}
return dec.Bytes()
}
// http://msdn.microsoft.com/en-us/library/ee780895.aspx
func decodeDateInt(buf []byte) (days int) {
return int(buf[0]) + int(buf[1])*256 + int(buf[2])*256*256
}
func decodeDate(buf []byte) time.Time {
return time.Date(1, 1, 1+decodeDateInt(buf), 0, 0, 0, 0, time.UTC)
}
func decodeTimeInt(scale uint8, buf []byte) (sec int, ns int) {
var acc uint64 = 0
for i := len(buf) - 1; i >= 0; i-- {
acc <<= 8
acc |= uint64(buf[i])
}
for i := 0; i < 7-int(scale); i++ {
acc *= 10
}
nsbig := acc * 100
sec = int(nsbig / 1000000000)
ns = int(nsbig % 1000000000)
return
}
func decodeTime(scale uint8, buf []byte) time.Time {
sec, ns := decodeTimeInt(scale, buf)
return time.Date(1, 1, 1, 0, 0, sec, ns, time.UTC)
}
func decodeDateTime2(scale uint8, buf []byte) time.Time {
timesize := len(buf) - 3
sec, ns := decodeTimeInt(scale, buf[:timesize])
days := decodeDateInt(buf[timesize:])
return time.Date(1, 1, 1+days, 0, 0, sec, ns, time.UTC)
}
func decodeDateTimeOffset(scale uint8, buf []byte) time.Time {
timesize := len(buf) - 3 - 2
sec, ns := decodeTimeInt(scale, buf[:timesize])
buf = buf[timesize:]
days := decodeDateInt(buf[:3])
buf = buf[3:]
offset := int(int16(binary.LittleEndian.Uint16(buf))) // in mins
return time.Date(1, 1, 1+days, 0, 0, sec+offset*60, ns,
time.FixedZone("", offset*60))
}
func divFloor(x int64, y int64) int64 {
q := x / y
r := x % y
if r != 0 && ((r < 0) != (y < 0)) {
q--
}
return q
}
func dateTime2(t time.Time) (days int32, ns int64) {
// number of days since Jan 1 1970 UTC
days64 := divFloor(t.Unix(), 24*60*60)
// number of days since Jan 1 1 UTC
days = int32(days64) + 1969*365 + 1969/4 - 1969/100 + 1969/400
// number of seconds within day
secs := t.Unix() - days64*24*60*60
// number of nanoseconds within day
ns = secs*1e9 + int64(t.Nanosecond())
return
}
func decodeChar(col collation, buf []byte) string {
return charset2utf8(col, buf)
}
func decodeUcs2(buf []byte) string {
res, err := ucs22str(buf)
if err != nil {
badStreamPanicf("Invalid UCS2 encoding: %s", err.Error())
}
return res
}
func decodeNChar(buf []byte) string {
return decodeUcs2(buf)
}
func decodeXml(ti typeInfo, buf []byte) string {
return decodeUcs2(buf)
}
func decodeUdt(ti typeInfo, buf []byte) int {
panic("Not implemented")
}
func makeDecl(ti typeInfo) string {
switch ti.TypeId {
case typeInt8:
return "bigint"
case typeFlt4:
return "real"
case typeIntN:
switch ti.Size {
case 1:
return "tinyint"
case 2:
return "smallint"
case 4:
return "int"
case 8:
return "bigint"
default:
panic("invalid size of INTNTYPE")
}
case typeFlt8:
return "float"
case typeFltN:
switch ti.Size {
case 4:
return "real"
case 8:
return "float"
default:
panic("invalid size of FLNNTYPE")
}
case typeBigVarBin:
if ti.Size > 8000 || ti.Size == 0 {
return fmt.Sprintf("varbinary(max)")
} else {
return fmt.Sprintf("varbinary(%d)", ti.Size)
}
case typeNVarChar:
if ti.Size > 8000 || ti.Size == 0 {
return fmt.Sprintf("nvarchar(max)")
} else {
return fmt.Sprintf("nvarchar(%d)", ti.Size/2)
}
case typeBit, typeBitN:
return "bit"
case typeDateTimeN:
return "datetime"
case typeDateTimeOffsetN:
return fmt.Sprintf("datetimeoffset(%d)", ti.Scale)
default:
panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId))
}
}