예제 #1
0
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
}
예제 #2
0
//
// 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
}
예제 #3
0
//
// 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
}
예제 #4
0
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
}
예제 #5
0
//
// 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
}
예제 #6
0
//
// 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
}
예제 #7
0
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
}