1 Star 0 Fork 0

wlhet / orago

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
parameter_encode.go 13.89 KB
一键复制 编辑 原始数据 按行查看 历史
wlhet 提交于 2023-02-10 15:17 . 对应 go-ora v2.5.27
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
package orago
import (
"bytes"
"database/sql"
"database/sql/driver"
"errors"
"reflect"
"time"
"gitee.com/wlhet/orago/converters"
)
func (par *ParameterInfo) setForNull() {
par.DataType = NCHAR
par.BValue = nil
par.ContFlag = 0
par.MaxCharLen = 0
par.MaxLen = 1
par.CharsetForm = 1
}
func (par *ParameterInfo) setForNumber() {
par.DataType = NUMBER
par.ContFlag = 0
par.MaxCharLen = 0
par.MaxLen = converters.MAX_LEN_NUMBER
par.CharsetForm = 0
par.CharsetID = 0
}
func (par *ParameterInfo) setForTime() {
par.DataType = DATE
par.ContFlag = 0
par.MaxLen = converters.MAX_LEN_DATE
par.CharsetID = 0
par.CharsetForm = 0
}
func (par *ParameterInfo) setForRefCursor() {
par.BValue = nil
par.MaxCharLen = 0
par.MaxLen = 1
par.DataType = REFCURSOR
par.ContFlag = 0
par.CharsetForm = 0
}
func (par *ParameterInfo) setForUDT() {
par.Flag = 3
par.Version = 1
par.DataType = XMLType
par.CharsetID = 0
par.CharsetForm = 0
par.MaxLen = 2000
}
func (par *ParameterInfo) encodeInt(value int64) {
par.setForNumber()
par.BValue = converters.EncodeInt64(value)
}
func (par *ParameterInfo) encodeFloat(value float64) error {
par.setForNumber()
var err error
par.BValue, err = converters.EncodeDouble(value)
return err
}
func (par *ParameterInfo) encodeString(value string, converter converters.IStringConverter, size int) {
par.DataType = NCHAR
par.ContFlag = 16
par.MaxCharLen = len([]rune(value))
if len(value) == 0 {
par.BValue = nil
} else {
if converter.GetLangID() != par.CharsetID {
tempCharset := converter.SetLangID(par.CharsetID)
par.BValue = converter.Encode(value)
converter.SetLangID(tempCharset)
} else {
par.BValue = converter.Encode(value)
}
}
if size > len(value) {
par.MaxCharLen = size
}
if par.Direction == Input {
if par.BValue == nil {
par.MaxLen = 1
} else {
par.MaxLen = len(par.BValue)
}
} else {
par.MaxLen = par.MaxCharLen * converters.MaxBytePerChar(par.CharsetID)
}
}
func (par *ParameterInfo) encodeTime(value time.Time) {
par.setForTime()
par.BValue = converters.EncodeDate(value)
}
func (par *ParameterInfo) encodeTimeStamp(value TimeStamp) {
par.setForTime()
par.DataType = TIMESTAMP
par.BValue = converters.EncodeTimeStamp(time.Time(value))
}
func (par *ParameterInfo) encodeRaw(value []byte, size int) {
par.BValue = value
par.DataType = RAW
par.MaxLen = len(value)
if size > par.MaxLen {
par.MaxLen = size
}
par.ContFlag = 0
par.MaxCharLen = 0
par.CharsetForm = 0
par.CharsetID = 0
}
func (par *ParameterInfo) encodeValue(val driver.Value, size int, connection *Connection) error {
var err error
par.Value = val
if val == nil {
par.setForNull()
return nil
}
// put common values
par.Flag = 3
par.CharsetID = connection.tcpNego.ServerCharset
par.CharsetForm = 1
par.BValue = nil
tempType := reflect.TypeOf(val)
if tempType.Kind() == reflect.Ptr {
tempType = tempType.Elem()
}
if tempType != reflect.TypeOf([]byte{}) {
if tempType.Kind() == reflect.Array || tempType.Kind() == reflect.Slice {
return par.encodeArrayValue(val, size, connection)
}
}
if temp, ok := val.(driver.Valuer); ok {
if temp == nil || (reflect.ValueOf(temp).Kind() == reflect.Ptr && reflect.ValueOf(temp).IsNil()) {
// bypass nil pointer
} else {
tempVal, err := temp.Value()
if err != nil {
return err
}
if tempVal == nil {
switch val.(type) {
case sql.NullInt32:
par.setForNumber()
case sql.NullBool:
par.setForNumber()
case sql.NullTime:
par.setForTime()
case sql.NullByte:
par.setForNumber()
case sql.NullFloat64:
par.setForNumber()
case sql.NullInt16:
par.setForNumber()
case sql.NullInt64:
par.setForNumber()
case sql.NullString:
par.encodeString("", nil, size)
case NullNVarChar:
par.CharsetForm = 2
par.CharsetID = connection.tcpNego.ServernCharset
par.encodeString("", nil, size)
case NullTimeStamp:
par.setForTime()
par.DataType = TIMESTAMP
case *sql.NullInt32:
par.setForNumber()
case *sql.NullBool:
par.setForNumber()
case *sql.NullTime:
par.setForTime()
case *sql.NullByte:
par.setForNumber()
case *sql.NullFloat64:
par.setForNumber()
case *sql.NullInt16:
par.setForNumber()
case *sql.NullInt64:
par.setForNumber()
case *sql.NullString:
par.encodeString("", nil, size)
case *NullNVarChar:
par.CharsetForm = 2
par.CharsetID = connection.tcpNego.ServernCharset
par.encodeString("", nil, size)
case *NullTimeStamp:
par.setForTime()
par.DataType = TIMESTAMP
default:
par.encodeString("", nil, size)
}
return nil
} else {
val = tempVal
}
}
}
switch value := val.(type) {
case int:
par.encodeInt(int64(value))
case int8:
par.encodeInt(int64(value))
case int16:
par.encodeInt(int64(value))
case int32:
par.encodeInt(int64(value))
case int64:
par.encodeInt(value)
case *int:
if value == nil {
par.setForNumber()
} else {
par.encodeInt(int64(*value))
}
case *int8:
if value == nil {
par.setForNumber()
} else {
par.encodeInt(int64(*value))
}
case *int16:
if value == nil {
par.setForNumber()
} else {
par.encodeInt(int64(*value))
}
case *int32:
if value == nil {
par.setForNumber()
} else {
par.encodeInt(int64(*value))
}
case *int64:
if value == nil {
par.setForNumber()
} else {
par.encodeInt(*value)
}
case uint:
par.encodeInt(int64(value))
case uint8:
par.encodeInt(int64(value))
case uint16:
par.encodeInt(int64(value))
case uint32:
par.encodeInt(int64(value))
case uint64:
par.encodeInt(int64(value))
case *uint:
if value == nil {
par.setForNumber()
} else {
par.encodeInt(int64(*value))
}
case *uint8:
if value == nil {
par.setForNumber()
} else {
par.encodeInt(int64(*value))
}
case *uint16:
if value == nil {
par.setForNumber()
} else {
par.encodeInt(int64(*value))
}
case *uint32:
if value == nil {
par.setForNumber()
} else {
par.encodeInt(int64(*value))
}
case *uint64:
if value == nil {
par.setForNumber()
} else {
par.encodeInt(int64(*value))
}
case float32:
err = par.encodeFloat(float64(value))
if err != nil {
return err
}
case float64:
err = par.encodeFloat(value)
if err != nil {
return err
}
case *float32:
if value == nil {
par.setForNumber()
} else {
err = par.encodeFloat(float64(*value))
if err != nil {
return err
}
}
case *float64:
if value == nil {
par.setForNumber()
} else {
err = par.encodeFloat(*value)
if err != nil {
return err
}
}
case time.Time:
par.encodeTime(value)
case *time.Time:
par.encodeTime(*value)
case TimeStamp:
par.encodeTimeStamp(value)
case *TimeStamp:
if value == nil {
par.setForTime()
par.DataType = TIMESTAMP
} else {
par.encodeTimeStamp(*value)
}
case NClob:
par.CharsetForm = 2
par.CharsetID = connection.tcpNego.ServernCharset
par.encodeString(value.String, connection.strConv, size)
if par.Direction == Output {
par.DataType = OCIClobLocator
} else {
if par.MaxLen >= converters.MAX_LEN_NVARCHAR2 {
par.DataType = OCIClobLocator
lob := newLob(connection)
err = lob.createTemporaryClob(connection.tcpNego.ServernCharset, 2)
if err != nil {
return err
}
err = lob.putString(value.String, connection.tcpNego.ServernCharset)
if err != nil {
return err
}
value.locator = lob.sourceLocator
par.BValue = lob.sourceLocator
par.Value = value
}
}
case *NClob:
par.CharsetForm = 2
par.CharsetID = connection.tcpNego.ServernCharset
par.encodeString(value.String, connection.strConv, size)
if par.Direction == Output {
par.DataType = OCIClobLocator
} else {
if par.MaxLen >= converters.MAX_LEN_NVARCHAR2 {
par.DataType = OCIClobLocator
lob := newLob(connection)
err = lob.createTemporaryClob(connection.tcpNego.ServernCharset, 2)
if err != nil {
return err
}
err = lob.putString(value.String, connection.tcpNego.ServernCharset)
if err != nil {
return err
}
value.locator = lob.sourceLocator
par.BValue = lob.sourceLocator
}
}
case Clob:
par.encodeString(value.String, connection.strConv, size)
if par.Direction == Output {
par.DataType = OCIClobLocator
} else {
if par.MaxLen >= converters.MAX_LEN_VARCHAR2 {
// here we need to use clob
par.DataType = OCIClobLocator
lob := newLob(connection)
err = lob.createTemporaryClob(connection.tcpNego.ServerCharset, 1)
if err != nil {
return err
}
err = lob.putString(value.String, connection.tcpNego.ServerCharset)
if err != nil {
return err
}
value.locator = lob.sourceLocator
par.BValue = lob.sourceLocator
par.Value = value
}
}
case *Clob:
if value == nil {
par.encodeString("", connection.strConv, size)
} else {
par.encodeString(value.String, connection.strConv, size)
}
if par.Direction == Output {
par.DataType = OCIClobLocator
} else {
if par.MaxLen >= converters.MAX_LEN_VARCHAR2 {
par.DataType = OCIClobLocator
lob := newLob(connection)
err = lob.createTemporaryClob(connection.tcpNego.ServerCharset, 1)
if err != nil {
return err
}
err = lob.putString(value.String, connection.tcpNego.ServerCharset)
if err != nil {
return err
}
value.locator = lob.sourceLocator
par.BValue = lob.sourceLocator
}
}
case BFile:
par.encodeRaw(nil, size)
if par.MaxLen == 0 {
par.MaxLen = 4000
}
par.DataType = OCIFileLocator
if par.Direction == Input {
if !value.isInit() {
return errors.New("BFile must be initialized")
}
par.BValue = value.lob.sourceLocator
}
case *BFile:
par.encodeRaw(nil, size)
if par.MaxLen == 0 {
par.MaxLen = 4000
}
par.DataType = OCIFileLocator
if par.Direction == Input {
if !value.isInit() {
return errors.New("BFile must be initialized")
}
par.BValue = value.lob.sourceLocator
}
case Blob:
par.encodeRaw(value.Data, size)
if par.MaxLen == 0 {
par.MaxLen = 1
}
if par.Direction == Output {
par.DataType = OCIBlobLocator
} else {
if len(value.Data) >= converters.MAX_LEN_RAW {
par.DataType = OCIBlobLocator
lob := newLob(connection)
err = lob.createTemporaryBLOB()
if err != nil {
return err
}
err = lob.putData(value.Data)
if err != nil {
return err
}
value.locator = lob.sourceLocator
par.BValue = lob.sourceLocator
par.Value = value
}
}
case *Blob:
if value == nil {
par.encodeRaw(nil, size)
} else {
par.encodeRaw(value.Data, size)
}
if par.MaxLen == 0 {
par.MaxLen = 1
}
if par.Direction == Output {
par.DataType = OCIBlobLocator
} else {
if len(value.Data) >= converters.MAX_LEN_RAW {
par.DataType = OCIBlobLocator
lob := newLob(connection)
err = lob.createTemporaryBLOB()
if err != nil {
return err
}
err = lob.putData(value.Data)
if err != nil {
return err
}
value.locator = lob.sourceLocator
par.BValue = lob.sourceLocator
}
}
case []byte:
if len(value) > converters.MAX_LEN_RAW && par.Direction == Input {
return par.encodeValue(Blob{Valid: true, Data: value}, size, connection)
}
par.encodeRaw(value, size)
case *[]byte:
if value == nil {
par.encodeRaw(nil, size)
} else {
if len(*value) > converters.MAX_LEN_RAW && par.Direction == Input {
return par.encodeValue(&Blob{Valid: true, Data: *value}, size, connection)
}
par.encodeRaw(*value, size)
}
case RefCursor, *RefCursor:
par.setForRefCursor()
case string:
if len(value) > converters.MAX_LEN_NVARCHAR2 && par.Direction == Input {
return par.encodeValue(Clob{Valid: true, String: value}, size, connection)
}
par.encodeString(value, connection.strConv, size)
case *string:
if value == nil {
par.encodeString("", connection.strConv, size)
} else {
if len(*value) > converters.MAX_LEN_NVARCHAR2 && par.Direction == Input {
return par.encodeValue(&Clob{Valid: true, String: *value}, size, connection)
}
par.encodeString(*value, connection.strConv, size)
}
case NVarChar:
par.CharsetForm = 2
par.CharsetID = connection.tcpNego.ServernCharset
par.encodeString(string(value), connection.strConv, size)
case *NVarChar:
par.CharsetForm = 2
par.CharsetID = connection.tcpNego.ServernCharset
if value == nil {
par.encodeString("", connection.strConv, size)
} else {
par.encodeString(string(*value), connection.strConv, size)
}
case *sql.NullBool:
par.setForNumber()
case *sql.NullByte:
par.setForNumber()
case *sql.NullInt16:
par.setForNumber()
case *sql.NullInt32:
par.setForNumber()
case *sql.NullInt64:
par.setForNumber()
case *sql.NullTime:
par.setForTime()
case *sql.NullFloat64:
par.setForNumber()
case *sql.NullString:
par.encodeString("", nil, size)
case *NullNVarChar:
par.encodeString("", nil, size)
par.CharsetForm = 2
par.CharsetID = connection.tcpNego.ServernCharset
case *NullTimeStamp:
par.setForTime()
par.DataType = TIMESTAMP
default:
custVal := reflect.ValueOf(val)
if custVal.Kind() == reflect.Ptr {
custVal = custVal.Elem()
}
if custVal.Kind() == reflect.Struct {
par.setForUDT()
for _, cusTyp := range connection.cusTyp {
if custVal.Type() == cusTyp.typ {
par.cusType = &cusTyp
par.ToID = cusTyp.toid
}
}
if par.cusType == nil {
return errors.New("struct parameter only allowed with user defined type (UDT)")
}
var objectBuffer bytes.Buffer
for _, attrib := range par.cusType.attribs {
if fieldIndex, ok := par.cusType.filedMap[attrib.Name]; ok {
tempPar := ParameterInfo{
Direction: par.Direction,
Flag: 3,
CharsetID: connection.tcpNego.ServerCharset,
CharsetForm: 1,
}
err = tempPar.encodeValue(custVal.Field(fieldIndex).Interface(), 0, connection)
if err != nil {
return err
}
connection.session.WriteClr(&objectBuffer, tempPar.BValue)
}
}
par.BValue = objectBuffer.Bytes()
}
}
return nil
}
1
https://gitee.com/wlhet/orago.git
git@gitee.com:wlhet/orago.git
wlhet
orago
orago
v1.0.0

搜索帮助

53164aa7 5694891 3bd8fe86 5694891