func readClassname(buf io.Reader) (string, error) { var ( cnameLen int32 cnameBytes []byte err error ) cnameLen, err = varint.ReadVarIntAndDecode32(buf) if err != nil { return "", oerror.NewTrace(err) } if cnameLen < 0 { return "", oerror.NewTrace( fmt.Errorf("Varint for classname len in binary serialization was negative: %d", cnameLen)) } cnameBytes = make([]byte, int(cnameLen)) n, err := buf.Read(cnameBytes) if err != nil { return "", oerror.NewTrace(err) } if n != int(cnameLen) { return "", fmt.Errorf("Could not read expected number of bytes for className. Expected %d; Read: %d", cnameLen, len(cnameBytes)) } return string(cnameBytes), nil }
// // Returns map of string keys to *oschema.OLink // func (serde ORecordSerializerV0) readLinkMap(buf io.Reader) (map[string]*oschema.OLink, error) { nentries, err := varint.ReadVarIntAndDecode32(buf) if err != nil { return nil, oerror.NewTrace(err) } linkMap := make(map[string]*oschema.OLink) for i := 0; i < int(nentries); i++ { /* ---[ read map key ]--- */ datatype, err := rw.ReadByte(buf) if err != nil { return nil, oerror.NewTrace(err) } if datatype != byte(oschema.STRING) { // FIXME: even though all keys are currently strings, it would be easy to allow other types // using serde.readDataValue(dbc, buf, serde) return nil, fmt.Errorf("readLinkMap: datatype for key is NOT string but type: %v", datatype) } mapkey, err := varint.ReadString(buf) if err != nil { return nil, oerror.NewTrace(err) } /* ---[ read map value (always a RID) ]--- */ mapval, err := serde.readLink(buf) if err != nil { return nil, oerror.NewTrace(err) } linkMap[mapkey] = mapval } return linkMap, nil }
// // readEmbeddedMap handles the EMBEDDEDMAP type. Currently, OrientDB only uses string // types for the map keys, so that is an assumption of this method as well. // // TODO: change return type to (*oschema.OEmbeddedMap, error) { ??? func (serde ORecordSerializerV0) readEmbeddedMap(buf *obuf.ReadBuf) (map[string]interface{}, error) { numRecs, err := varint.ReadVarIntAndDecode32(buf) if err != nil { return nil, oerror.NewTrace(err) } nrecs := int(numRecs) m := make(map[string]interface{}) // final map to be returned // data structures for reading the map header section, which gives key names and // value types (and value ptrs, but I don't need those for the way I parse the data) keynames := make([]string, nrecs) valtypes := make([]oschema.ODataType, nrecs) // read map headers for i := 0; i < nrecs; i++ { keytype, err := rw.ReadByte(buf) if err != nil { return nil, oerror.NewTrace(err) } if keytype != byte(oschema.STRING) { panic(fmt.Sprintf("ReadEmbeddedMap got a key datatype %v - but it should be 7 (string)", keytype)) } keynames[i], err = varint.ReadString(buf) if err != nil { return nil, oerror.NewTrace(err) } _, err = rw.ReadInt(buf) // pointer - throwing away if err != nil { return nil, oerror.NewTrace(err) } b, err := rw.ReadByte(buf) if err != nil { return nil, oerror.NewTrace(err) } valtypes[i] = oschema.ODataType(b) } // read map values for i := 0; i < nrecs; i++ { val, err := serde.readDataValue(buf, valtypes[i]) if err != nil { return nil, oerror.NewTrace(err) } m[keynames[i]] = val } return m, nil }
func (serde ORecordSerializerV0) readLinkList(buf io.Reader) ([]*oschema.OLink, error) { nrecs, err := varint.ReadVarIntAndDecode32(buf) if err != nil { return nil, oerror.NewTrace(err) } links := make([]*oschema.OLink, int(nrecs)) for i := range links { lnk, err := serde.readLink(buf) if err != nil { return nil, oerror.NewTrace(err) } links[i] = lnk } return links, nil }
// // readEmbeddedCollection handles both EMBEDDEDLIST and EMBEDDEDSET types. // Java client API: // Collection<?> readEmbeddedCollection(BytesContainer bytes, Collection<Object> found, ODocument document) { // `found`` gets added to during the recursive iterations // func (serde ORecordSerializerV0) readEmbeddedCollection(buf *obuf.ReadBuf) ([]interface{}, error) { nrecs, err := varint.ReadVarIntAndDecode32(buf) if err != nil { return nil, oerror.NewTrace(err) } datatype, err := rw.ReadByte(buf) if err != nil { return nil, oerror.NewTrace(err) } if datatype != byte(oschema.ANY) { // OrientDB server always returns ANY // NOTE: currently the Java client doesn't handle this case either, so safe for now panic(fmt.Sprintf("ReadEmbeddedList got a datatype %v - currently that datatype is not supported", datatype)) } ary := make([]interface{}, int(nrecs)) // loop over all recs for i := range ary { // if type is ANY (unknown), then the next byte specifies the type of record to follow b, err := rw.ReadByte(buf) if err != nil { return nil, oerror.NewTrace(err) } itemtype := oschema.ODataType(b) if itemtype == oschema.ANY { ary[i] = nil // this is what the Java client does continue } val, err := serde.readDataValue(buf, itemtype) if err != nil { return nil, oerror.NewTrace(err) } ary[i] = val } return ary, nil }
// // readDataValue reads the next data section from `buf` according // to the type of the property (property.Typ) and updates the OField object // to have the value. // func (serde ORecordSerializerV0) readDataValue(buf *obuf.ReadBuf, datatype oschema.ODataType) (interface{}, error) { var ( val interface{} err error ) switch datatype { case oschema.BOOLEAN: val, err = rw.ReadBool(buf) ogl.Debugf("DEBUG BOOL: +readDataVal val: %v\n", val) // DEBUG case oschema.INTEGER: var i64 int64 i64, err = varint.ReadVarIntAndDecode64(buf) if err == nil { val = int32(i64) } ogl.Debugf("DEBUG INT: +readDataVal val: %v\n", val) // DEBUG case oschema.SHORT: var i32 int32 i32, err = varint.ReadVarIntAndDecode32(buf) if err == nil { val = int16(i32) } ogl.Debugf("DEBUG SHORT: +readDataVal val: %v\n", val) // DEBUG case oschema.LONG: val, err = varint.ReadVarIntAndDecode64(buf) ogl.Debugf("DEBUG LONG: +readDataVal val: %v\n", val) // DEBUG case oschema.FLOAT: val, err = rw.ReadFloat(buf) ogl.Debugf("DEBUG FLOAT: +readDataVal val: %v\n", val) // DEBUG case oschema.DOUBLE: val, err = rw.ReadDouble(buf) ogl.Debugf("DEBUG DOUBLE: +readDataVal val: %v\n", val) // DEBUG case oschema.DATETIME: // OrientDB DATETIME is precise to the second val, err = serde.readDateTime(buf) ogl.Debugf("DEBUG DATEIME: +readDataVal val: %v\n", val) // DEBUG case oschema.DATE: // OrientDB DATE is precise to the day val, err = serde.readDate(buf) ogl.Debugf("DEBUG DATE: +readDataVal val: %v\n", val) // DEBUG case oschema.STRING: val, err = varint.ReadString(buf) ogl.Debugf("DEBUG STR: +readDataVal val: %v\n", val) // DEBUG case oschema.BINARY: val, err = varint.ReadBytes(buf) ogl.Debugf("DEBUG BINARY: +readDataVal val: %v\n", val) // DEBUG case oschema.EMBEDDED: doc := oschema.NewDocument("") err = serde.Deserialize(nil, doc, buf) val = interface{}(doc) // ogl.Debugf("DEBUG EMBEDDEDREC: +readDataVal val: %v\n", val) // DEBUG case oschema.EMBEDDEDLIST: val, err = serde.readEmbeddedCollection(buf) // ogl.Debugf("DEBUG EMBD-LIST: +readDataVal val: %v\n", val) // DEBUG case oschema.EMBEDDEDSET: val, err = serde.readEmbeddedCollection(buf) // TODO: may need to create a set type as well // ogl.Debugf("DEBUG EMBD-SET: +readDataVal val: %v\n", val) // DEBUG case oschema.EMBEDDEDMAP: val, err = serde.readEmbeddedMap(buf) // ogl.Debugf("DEBUG EMBD-MAP: +readDataVal val: %v\n", val) // DEBUG case oschema.LINK: // a link is two int64's (cluster:record) - we translate it here to a string RID val, err = serde.readLink(buf) ogl.Debugf("DEBUG LINK: +readDataVal val: %v\n", val) // DEBUG case oschema.LINKLIST, oschema.LINKSET: val, err = serde.readLinkList(buf) ogl.Debugf("DEBUG LINK LIST/SET: +readDataVal val: %v\n", val) // DEBUG case oschema.LINKMAP: val, err = serde.readLinkMap(buf) ogl.Debugf("DEBUG LINKMap: +readDataVal val: %v\n", val) // DEBUG case oschema.BYTE: val, err = rw.ReadByte(buf) ogl.Debugf("DEBUG BYTE: +readDataVal val: %v\n", val) // DEBUG case oschema.LINKBAG: val, err = serde.readLinkBag(buf) ogl.Debugf("DEBUG LINKBAG: +readDataVal val: %v\n", val) // DEBUG case oschema.CUSTOM: // TODO: impl me -> how? when is this used? panic("ORecordSerializerV0#readDataValue CUSTOM NOT YET IMPLEMENTED") case oschema.DECIMAL: // TODO: impl me -> Java client uses BigDecimal for this panic("ORecordSerializerV0#readDataValue DECIMAL NOT YET IMPLEMENTED") default: // ANY and TRANSIENT are do nothing ops } return val, err }
func readHeader(buf io.Reader) (header, error) { hdr := header{ properties: make([]headerProperty, 0, 8), dataPtrs: make([]int32, 0, 8), } for { decoded, err := varint.ReadVarIntAndDecode32(buf) if err != nil { _, _, line, _ := runtime.Caller(0) return header{}, fmt.Errorf("Error in binserde.readHeader (line %d): %v", line-2, err) } if decoded == 0 { // 0 marks end of header break } else if decoded > 0 { // have a property, not a document, so the number is a zigzag encoded length // for a string (property name) // read property name data := make([]byte, int(decoded)) n, err := buf.Read(data) if err != nil { return header{}, oerror.NewTrace(err) } if len(data) != n { return header{}, oerror.IncorrectNetworkRead{Expected: len(data), Actual: n} } // hdr.propertyNames = append(hdr.propertyNames, string(data)) // read data pointer ptr, err := rw.ReadInt(buf) if err != nil { return header{}, oerror.NewTrace(err) } // read data type bsDataType := make([]byte, 1) n, err = buf.Read(bsDataType) if err != nil { return header{}, oerror.NewTrace(err) } if n != 1 { return header{}, oerror.IncorrectNetworkRead{Expected: 1, Actual: n} } hdrProp := headerProperty{name: data, typ: oschema.ODataType(bsDataType[0])} hdr.properties = append(hdr.properties, hdrProp) hdr.dataPtrs = append(hdr.dataPtrs, ptr) } else { // have a document, not a property, so the number is an encoded property id, // convert to (positive) property-id propertyID := decodeFieldIDInHeader(decoded) ptr, err := rw.ReadInt(buf) if err != nil { return header{}, oerror.NewTrace(err) } hdrProp := headerProperty{id: propertyID} hdr.properties = append(hdr.properties, hdrProp) hdr.dataPtrs = append(hdr.dataPtrs, ptr) } } return hdr, nil }