Skip to content

Commit 2c22764

Browse files
committed
add support for nested UDT
1 parent 7187f6d commit 2c22764

File tree

4 files changed

+112
-69
lines changed

4 files changed

+112
-69
lines changed

v2/driver.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ func RegisterTypeWithOwner(conn *sql.DB, owner, typeName, arrayTypeName string,
167167
}
168168
sqlText = `SELECT ATTR_NAME, ATTR_TYPE_NAME, LENGTH, ATTR_NO
169169
FROM ALL_TYPE_ATTRS
170-
WHERE UPPER(OWNER)=:1 AND UPPER(TYPE_NAME)=:2`
170+
WHERE UPPER(OWNER)=:1 AND UPPER(TYPE_NAME)=:2
171+
ORDER BY ATTR_NO`
171172
rows, err := conn.Query(sqlText, strings.ToUpper(owner), strings.ToUpper(typeName))
172173
if err != nil {
173174
return err
@@ -183,13 +184,14 @@ func RegisterTypeWithOwner(conn *sql.DB, owner, typeName, arrayTypeName string,
183184
if err != nil {
184185
return err
185186
}
186-
for int(attOrder) > len(cust.attribs) {
187-
cust.attribs = append(cust.attribs, ParameterInfo{
188-
Direction: Input,
189-
Flag: 3,
190-
})
191-
}
192-
param := &cust.attribs[attOrder-1]
187+
//for int(attOrder) > len(cust.attribs) {
188+
// cust.attribs = append(cust.attribs, ParameterInfo{
189+
// Direction: Input,
190+
// Flag: 3,
191+
// })
192+
//}
193+
//param := &cust.attribs[attOrder-1]
194+
param := ParameterInfo{Direction: Input, Flag: 3}
193195
param.Name = attName.String
194196
param.TypeName = attTypeName.String
195197
switch strings.ToUpper(attTypeName.String) {
@@ -240,6 +242,7 @@ func RegisterTypeWithOwner(conn *sql.DB, owner, typeName, arrayTypeName string,
240242
for name, value := range driver.cusTyp {
241243
if name == strings.ToUpper(attTypeName.String) {
242244
found = true
245+
//param.DataType = XMLType
243246
param.cusType = new(customType)
244247
*param.cusType = value
245248
param.ToID = value.toid
@@ -257,6 +260,7 @@ func RegisterTypeWithOwner(conn *sql.DB, owner, typeName, arrayTypeName string,
257260
return fmt.Errorf("unsupported attribute type: %s", attTypeName.String)
258261
}
259262
}
263+
cust.attribs = append(cust.attribs, param)
260264
}
261265
if len(cust.attribs) == 0 {
262266
return fmt.Errorf("unknown or empty type: %s", typeName)

v2/parameter_encode.go

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -180,15 +180,15 @@ func (par *ParameterInfo) setDataType(goType reflect.Type, value driver.Value, c
180180
par.CharsetID = conn.tcpNego.ServernCharset
181181
case tyTime, tyNullTime:
182182
if par.Direction == Input {
183-
par.DataType = TimeStampTZ_DTY
183+
par.DataType = TIMESTAMP
184184
par.MaxLen = converters.MAX_LEN_TIMESTAMP
185185
} else {
186186
par.DataType = DATE
187187
par.MaxLen = converters.MAX_LEN_DATE
188188
}
189189
case tyTimeStamp, tyNullTimeStamp:
190190
if par.Direction == Input {
191-
par.DataType = TimeStampTZ_DTY
191+
par.DataType = TIMESTAMP
192192
par.MaxLen = converters.MAX_LEN_TIMESTAMP
193193
} else {
194194
par.DataType = TIMESTAMP
@@ -370,31 +370,26 @@ func (par *ParameterInfo) encodeWithType(connection *Connection) error {
370370
case XMLType:
371371
rValue := reflect.ValueOf(val)
372372
var objectBuffer bytes.Buffer
373-
pars := make([]ParameterInfo, 0, 10)
374-
for _, attrib := range par.cusType.attribs {
375-
if fieldIndex, ok := par.cusType.fieldMap[attrib.Name]; ok {
376-
//tempPar := ParameterInfo{Direction: par.Direction, DataType: attrib.DataType}
377-
tempPar := attrib.clone()
378-
tempPar.Direction = par.Direction
379-
tempPar.Value = rValue.Field(fieldIndex).Interface()
380-
err = tempPar.encodeWithType(connection)
381-
if err != nil {
382-
return err
383-
}
384-
err = tempPar.encodePrimValue(connection)
385-
if err != nil {
386-
return err
373+
pars := getUDTAttributes(par.cusType, rValue)
387374

388-
}
389-
if tempPar.DataType == OCIFileLocator && tempPar.MaxLen == 0 {
390-
tempPar.MaxLen = 4000
391-
}
392-
if tempPar.Direction == Output {
393-
tempPar.BValue = nil
394-
}
395-
pars = append(pars, tempPar)
396-
connection.session.WriteClr(&objectBuffer, tempPar.BValue)
375+
for _, attrib := range pars {
376+
attrib.Direction = par.Direction
377+
err = attrib.encodeWithType(connection)
378+
if err != nil {
379+
return err
380+
}
381+
err = attrib.encodePrimValue(connection)
382+
if err != nil {
383+
return err
384+
385+
}
386+
if attrib.DataType == OCIFileLocator && attrib.MaxLen == 0 {
387+
attrib.MaxLen = 4000
388+
}
389+
if attrib.Direction == Output {
390+
attrib.BValue = nil
397391
}
392+
connection.session.WriteClr(&objectBuffer, attrib.BValue)
398393
}
399394
par.iPrimValue = pars
400395
par.BValue = objectBuffer.Bytes()

v2/udt.go

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,16 @@ FROM ALL_TYPE_ATTRS WHERE UPPER(OWNER)=:1 AND UPPER(TYPE_NAME)=:2`
326326
// return nil
327327
//}
328328

329+
func (cust *customType) getFieldIndex(name string) int {
330+
for x := 0; x < cust.typ.NumField(); x++ {
331+
fieldID, _, _, _ := extractTag(cust.typ.Field(x).Tag.Get("udt"))
332+
if strings.ToUpper(fieldID) == strings.ToUpper(name) {
333+
return x
334+
}
335+
}
336+
return -1
337+
}
338+
329339
// loadFieldMap read struct tag that supplied with golang type object passed in RegisterType
330340
// function
331341
func (cust *customType) loadFieldMap() {
@@ -363,34 +373,33 @@ func (cust *customType) loadFieldMap() {
363373
// getObject return an object of Golang type supplied in RegisterType function
364374
// the object is filled with data from attrib []ParameterInfo
365375
// which is filled inside Stmt during data reading
366-
func (cust *customType) getObject() (interface{}, error) {
367-
typ := cust.typ
368-
obj := reflect.New(typ)
369-
for _, attrib := range cust.attribs {
370-
if fieldIndex, ok := cust.fieldMap[attrib.Name]; ok {
371-
if attrib.Value != nil {
372-
//tempField := obj.Elem().Field(fieldIndex)
373-
374-
//err := setValue(&tempField, attrib.Value)
375-
//if err != nil {
376-
// panic(err)
377-
//}
378-
tempPar := ParameterInfo{Value: obj.Elem().Field(fieldIndex).Interface()}
379-
err := tempPar.setParameterValue(attrib.Value)
380-
if err != nil {
381-
return nil, err
382-
}
383-
err = setFieldValue(obj.Elem().Field(fieldIndex), tempPar.cusType, tempPar.Value)
384-
if err != nil {
385-
return nil, err
386-
}
387-
//obj.Elem().Field(fieldIndex).Set(reflect.ValueOf(tempPar.Value))
388-
}
389-
}
390-
}
391-
return obj.Elem().Interface(), nil
392-
}
393-
376+
//func (cust *customType) getObject() (interface{}, error) {
377+
// typ := cust.typ
378+
// obj := reflect.New(typ)
379+
// for _, attrib := range cust.attribs {
380+
// if fieldIndex, ok := cust.fieldMap[attrib.Name]; ok {
381+
// if attrib.Value != nil {
382+
// //tempField := obj.Elem().Field(fieldIndex)
383+
//
384+
// //err := setValue(&tempField, attrib.Value)
385+
// //if err != nil {
386+
// // panic(err)
387+
// //}
388+
// tempPar := ParameterInfo{Value: obj.Elem().Field(fieldIndex).Interface()}
389+
// err := tempPar.setParameterValue(attrib.Value)
390+
// if err != nil {
391+
// return nil, err
392+
// }
393+
// err = setFieldValue(obj.Elem().Field(fieldIndex), attrib.cusType, attrib.Value)
394+
// if err != nil {
395+
// return nil, err
396+
// }
397+
// //obj.Elem().Field(fieldIndex).Set(reflect.ValueOf(tempPar.Value))
398+
// }
399+
// }
400+
// }
401+
// return obj.Elem().Interface(), nil
402+
//}
394403
//func (cust *customType) getFieldRepr(index int, input_value interface{}) ([]byte, error) {
395404
// attrib := cust.attribs[index]
396405
// //typ := reflect.TypeOf(val)

v2/utils.go

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,41 @@ func encodeObject(session *network.Session, objectData []byte, isArray bool) []b
11041104
fieldsData.Write(objectData)
11051105
return fieldsData.Bytes()
11061106
}
1107-
1107+
func putUDTAttributes(input *customType, pars []ParameterInfo, index int) ([]ParameterInfo, int) {
1108+
oPrimValue := make([]ParameterInfo, 0, len(input.attribs))
1109+
for _, attrib := range input.attribs {
1110+
if attrib.cusType == nil {
1111+
oPrimValue = append(oPrimValue, pars[index])
1112+
index++
1113+
} else {
1114+
var tempValue []ParameterInfo
1115+
tempValue, index = putUDTAttributes(attrib.cusType, pars, index)
1116+
attrib.oPrimValue = tempValue
1117+
oPrimValue = append(oPrimValue, attrib)
1118+
}
1119+
}
1120+
return oPrimValue, index
1121+
}
1122+
func getUDTAttributes(input *customType, value reflect.Value) []ParameterInfo {
1123+
output := make([]ParameterInfo, 0, 10)
1124+
for _, attrib := range input.attribs {
1125+
fieldValue := reflect.Value{}
1126+
if value.IsValid() && value.Kind() == reflect.Struct {
1127+
if fieldIndex, ok := input.fieldMap[attrib.Name]; ok {
1128+
fieldValue = value.Field(fieldIndex)
1129+
}
1130+
}
1131+
if attrib.cusType != nil {
1132+
output = append(output, getUDTAttributes(attrib.cusType, fieldValue)...)
1133+
} else {
1134+
if fieldValue.IsValid() {
1135+
attrib.Value = fieldValue.Interface()
1136+
}
1137+
output = append(output, attrib)
1138+
}
1139+
}
1140+
return output
1141+
}
11081142
func decodeObject(conn *Connection, parent *ParameterInfo, temporaryLobs *[][]byte) error {
11091143
session := conn.session
11101144
newState := network.SessionState{InBuffer: parent.BValue}
@@ -1163,17 +1197,18 @@ func decodeObject(conn *Connection, parent *ParameterInfo, temporaryLobs *[][]by
11631197
}
11641198
parent.oPrimValue = pars
11651199
case 0x84:
1166-
pars := make([]ParameterInfo, 0, len(parent.cusType.attribs))
1167-
for _, attrib := range parent.cusType.attribs {
1168-
tempPar := attrib
1169-
tempPar.Direction = parent.Direction
1170-
err = tempPar.decodePrimValue(conn, temporaryLobs, true)
1200+
//pars := make([]ParameterInfo, 0, len(parent.cusType.attribs))
1201+
// collect all attributes in one list
1202+
pars := getUDTAttributes(parent.cusType, reflect.Value{})
1203+
for index, _ := range pars {
1204+
pars[index].Direction = parent.Direction
1205+
err = pars[index].decodePrimValue(conn, temporaryLobs, true)
11711206
if err != nil {
11721207
return err
11731208
}
1174-
pars = append(pars, tempPar)
11751209
}
1176-
parent.oPrimValue = pars
1210+
// fill pars in its place in sub types
1211+
parent.oPrimValue, _ = putUDTAttributes(parent.cusType, pars, 0)
11771212
}
11781213
_ = session.LoadState()
11791214
return nil

0 commit comments

Comments
 (0)