// // Example data section for tree-based LinkBag // // ( --------------------- collectionPointer ----------------------- ) (---size:int--) (-changes-) // (----- fileId:long ----) ( ---pageIndex:long--- ) (pageOffset:int) // TREEBASED 30 0 2048 -1 0 // 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, -1, -1, -1, -1, 0, 0, 0, 0, // func readTreeBasedLinkBag(buf io.Reader) (*oschema.OLinkBag, error) { fileID, err := rw.ReadLong(buf) if err != nil { return nil, oerror.NewTrace(err) } pageIdx, err := rw.ReadLong(buf) if err != nil { return nil, oerror.NewTrace(err) } pageOffset, err := rw.ReadInt(buf) if err != nil { return nil, oerror.NewTrace(err) } // TODO: need to know how to handle the size and changes stuff => advanced feature not needed yet size, err := rw.ReadInt(buf) if err != nil { return nil, oerror.NewTrace(err) } _, err = rw.ReadInt(buf) // changes // TODO: is changes always an int32? if err != nil { return nil, oerror.NewTrace(err) } return oschema.NewTreeOLinkBag(fileID, pageIdx, pageOffset, size), nil }
// // readSingleDocument is called by readSingleRecord when it has determined that the server // has sent a docuemnt ('d'), not flat data ('f') or raw bytes ('b'). // It should be called *after* the single byte below on the first line has been already // read and determined to be 'd'. The rest the stream (NOT including the EOT byte) will // be read. The serialized document will be turned into an oschema.ODocument. // // Writing byte (1 byte): 100 [OChannelBinaryServer] <- 'd'=document ('f'=flat data, 'b'=raw bytes) // Writing short (2 bytes): 11 [OChannelBinaryServer] <- cluster-id (RID part 1) // Writing long (8 bytes): 0 [OChannelBinaryServer] <- cluster-pos (RID part 2) // Writing int (4 bytes): 1 [OChannelBinaryServer] <- version // Writing bytes (4+26=30 bytes): [0, 14, 80, 97, 116, ... , 110, 107, 1] <- serialized record // func readSingleDocument(dbc *DBClient) (*oschema.ODocument, error) { clusterId, err := rw.ReadShort(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } clusterPos, err := rw.ReadLong(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } recVersion, err := rw.ReadInt(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } recBytes, err := rw.ReadBytes(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } rid := oschema.ORID{ClusterID: clusterId, ClusterPos: clusterPos} doc, err := createDocumentFromBytes(rid, recVersion, recBytes, dbc) ogl.Debugf("::single record doc:::::: %v\n", doc) return doc, err }
func readStatusCodeAndSessionId(dbc *DBClient) error { status, err := rw.ReadByte(dbc.conx) if err != nil { return oerror.NewTrace(err) } sessionId, err := rw.ReadInt(dbc.conx) if err != nil { return oerror.NewTrace(err) } if sessionId != dbc.sessionId { // FIXME: use of fmt.Errorf is an anti-pattern return fmt.Errorf("sessionId from server (%v) does not match client sessionId (%v)", sessionId, dbc.sessionId) } if status == RESPONSE_STATUS_ERROR { serverException, err := rw.ReadErrorResponse(dbc.conx) if err != nil { return oerror.NewTrace(err) } return serverException } return nil }
func readEmbeddedLinkBag(rdr io.Reader) (*oschema.OLinkBag, error) { bs := make([]byte, 1) n, err := rdr.Read(bs) if err != nil { return nil, oerror.NewTrace(err) } if n != 1 { return nil, oerror.IncorrectNetworkRead{Expected: 1, Actual: n} } if bs[0] == 1 { uuid, err := readLinkBagUUID(rdr) if err != nil { return nil, oerror.NewTrace(err) } ogl.Debugf("read uuid %v - now what?\n", uuid) } else { // if b wasn't zero, then there's no UUID and b was the first byte of an int32 // specifying the size of the embedded bag collection // TODO: I'm not sure this is the right thing - the OrientDB is pretty hazy on how this works switch rdr.(type) { case *bytes.Buffer: buf := rdr.(*bytes.Buffer) buf.UnreadByte() case *obuf.ReadBuf: buf := rdr.(*obuf.ReadBuf) buf.UnreadByte() default: panic("Unknown type of buffer in binserde#readEmbeddedLinkBag") } } bagsz, err := rw.ReadInt(rdr) if err != nil { return nil, oerror.NewTrace(err) } links := make([]*oschema.OLink, bagsz) for i := int32(0); i < bagsz; i++ { clusterID, err := rw.ReadShort(rdr) if err != nil { return nil, oerror.NewTrace(err) } clusterPos, err := rw.ReadLong(rdr) if err != nil { return nil, oerror.NewTrace(err) } orid := oschema.ORID{ClusterID: clusterID, ClusterPos: clusterPos} links[i] = &oschema.OLink{RID: orid} } return oschema.NewOLinkBag(links), nil }
func readAndValidateSessionId(rdr io.Reader, currentSessionId int32) error { sessionId, err := rw.ReadInt(rdr) if err != nil { return err } if sessionId != currentSessionId { return fmt.Errorf("sessionId from server (%v) does not match client sessionId (%v)", sessionId, currentSessionId) } return 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 }
// // Large LinkBags (aka RidBags) are stored on the server. To look up their // size requires a call to the database. The size is returned. Note that the // Size field of the linkBag is NOT updated. That is left for the caller to // decide whether to do. // func FetchSizeOfRemoteLinkBag(dbc *DBClient, linkBag *oschema.OLinkBag) (int, error) { dbc.buf.Reset() err := writeCommandAndSessionId(dbc, REQUEST_RIDBAG_GET_SIZE) if err != nil { return 0, oerror.NewTrace(err) } err = writeLinkBagCollectionPointer(dbc.buf, linkBag) if err != nil { return 0, oerror.NewTrace(err) } // changes => TODO: right now not supporting any change -> just writing empty changes err = rw.WriteBytes(dbc.buf, []byte{0, 0, 0, 0}) if err != nil { return 0, oerror.NewTrace(err) } // send to the OrientDB server _, err = dbc.conx.Write(dbc.buf.Bytes()) if err != nil { return 0, oerror.NewTrace(err) } /* ---[ Read Response ]--- */ err = readStatusCodeAndSessionId(dbc) if err != nil { return 0, oerror.NewTrace(err) } size, err := rw.ReadInt(dbc.conx) if err != nil { return 0, oerror.NewTrace(err) } return int(size), nil }
// // readResultSet should be called for collections (resultType = 'l') // from a SQLQuery call. // func readResultSet(dbc *DBClient) ([]*oschema.ODocument, error) { // for Collection // next val is: (collection-size:int) // and then each record is serialized according to format: // (0:short)(record-type:byte)(cluster-id:short)(cluster-position:long)(record-version:int)(record-content:bytes) resultSetSize, err := rw.ReadInt(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } rsize := int(resultSetSize) docs := make([]*oschema.ODocument, rsize) for i := 0; i < rsize; i++ { // TODO: move code below to readRecordInResultSet // this apparently should always be zero for serialized records -> not sure it's meaning zero, err := rw.ReadShort(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } if zero != int16(0) { return nil, fmt.Errorf("ERROR: readResultSet: expected short value of 0 but is %d", zero) } recType, err := rw.ReadByte(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } // TODO: may need to check recType here => not sure that clusterId, clusterPos and version follow next if // type is 'b' (raw bytes) or 'f' (flat record) // see the readSingleDocument method (and probably call that one instead?) clusterId, err := rw.ReadShort(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } clusterPos, err := rw.ReadLong(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } recVersion, err := rw.ReadInt(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } if recType == byte('d') { // Document var doc *oschema.ODocument rid := oschema.ORID{ClusterID: clusterId, ClusterPos: clusterPos} recBytes, err := rw.ReadBytes(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } doc, err = createDocumentFromBytes(rid, recVersion, recBytes, dbc) if err != nil { return nil, oerror.NewTrace(err) } docs[i] = doc } else { _, file, line, _ := runtime.Caller(0) return nil, fmt.Errorf("%v: %v: Record type %v is not yet supported", file, line+1, recType) } } // end for loop // end, err := rw.ReadByte(dbc.conx) // if err != nil { // return nil, oerror.NewTrace(err) // } // if end != byte(0) { // return nil, fmt.Errorf("Final Byte read from collection result set was not 0, but was: %v", end) // } return docs, nil }
// // UpdateRecord should be used update an existing record in the OrientDB database. // It does the REQUEST_RECORD_UPDATE OrientDB cmd (network binary protocol) // func UpdateRecord(dbc *DBClient, doc *oschema.ODocument) error { dbc.buf.Reset() err := writeCommandAndSessionId(dbc, REQUEST_RECORD_UPDATE) if err != nil { return oerror.NewTrace(err) } if doc.RID.ClusterID < 0 || doc.RID.ClusterPos < 0 { return errors.New("Document is not updateable - has negative RID values") } err = rw.WriteShort(dbc.buf, doc.RID.ClusterID) if err != nil { return oerror.NewTrace(err) } err = rw.WriteLong(dbc.buf, doc.RID.ClusterPos) if err != nil { return oerror.NewTrace(err) } // update-content flag err = rw.WriteBool(dbc.buf, true) if err != nil { return oerror.NewTrace(err) } // serialized-doc serde := dbc.RecordSerDes[int(dbc.serializationVersion)] // this writes the serialized record to dbc.buf serializedBytes, err := serde.Serialize(dbc, doc) if err != nil { return oerror.NewTrace(err) } err = rw.WriteBytes(dbc.buf, serializedBytes) if err != nil { return oerror.NewTrace(err) } // record version err = rw.WriteInt(dbc.buf, doc.Version) if err != nil { return oerror.NewTrace(err) } // record-type: document err = rw.WriteByte(dbc.buf, byte('d')) // TODO: how support 'b' (raw bytes) & 'f' (flat data)? if err != nil { return oerror.NewTrace(err) } // mode: synchronous err = rw.WriteByte(dbc.buf, 0x0) if err != nil { return oerror.NewTrace(err) } // send to the OrientDB server _, err = dbc.conx.Write(dbc.buf.Bytes()) if err != nil { return oerror.NewTrace(err) } /* ---[ Read Response ]--- */ err = readStatusCodeAndSessionId(dbc) if err != nil { return oerror.NewTrace(err) } doc.Version, err = rw.ReadInt(dbc.conx) if err != nil { return oerror.NewTrace(err) } nCollChanges, err := rw.ReadInt(dbc.conx) if err != nil { return oerror.NewTrace(err) } if nCollChanges != 0 { // if > 0, then have to deal with RidBag mgmt: // [(uuid-most-sig-bits:long)(uuid-least-sig-bits:long)(updated-file-id:long)(updated-page-index:long)(updated-page-offset:int)] panic("CreateRecord: Found case where number-collection-changes is not zero -> log case and impl code to handle") } return nil }
// // FetchEntriesOfRemoteLinkBag fills in the links of an OLinkBag that is remote // (tree-based) rather than embedded. This function will fill in the links // of the passed in OLinkBag, rather than returning the new links. The Links // will have RIDs only, not full Records (ODocuments). If you then want the // Records filled in, call the ResolveLinks function. // func FetchEntriesOfRemoteLinkBag(dbc *DBClient, linkBag *oschema.OLinkBag, inclusive bool) error { var ( firstLink *oschema.OLink linkSerde binserde.OBinaryTypeSerializer err error ) firstLink, err = FetchFirstKeyOfRemoteLinkBag(dbc, linkBag) if err != nil { return oerror.NewTrace(err) } dbc.buf.Reset() err = writeCommandAndSessionId(dbc, REQUEST_SBTREE_BONSAI_GET_ENTRIES_MAJOR) if err != nil { return oerror.NewTrace(err) } err = writeLinkBagCollectionPointer(dbc.buf, linkBag) if err != nil { return oerror.NewTrace(err) } typeByte := byte(9) linkSerde = binserde.TypeSerializers[typeByte] // the OLinkSerializer linkBytes, err := linkSerde.Serialize(firstLink) if err != nil { return oerror.NewTrace(err) } err = rw.WriteBytes(dbc.buf, linkBytes) if err != nil { return oerror.NewTrace(err) } err = rw.WriteBool(dbc.buf, inclusive) if err != nil { return oerror.NewTrace(err) } // copied from Java client OSBTreeBonsaiRemote#fetchEntriesMajor if dbc.binaryProtocolVersion >= 21 { err = rw.WriteInt(dbc.buf, 128) } // send to the OrientDB server _, err = dbc.conx.Write(dbc.buf.Bytes()) if err != nil { return oerror.NewTrace(err) } /* ---[ Read Response ]--- */ err = readStatusCodeAndSessionId(dbc) if err != nil { return oerror.NewTrace(err) } linkEntryBytes, err := rw.ReadBytes(dbc.conx) if err != nil { return oerror.NewTrace(err) } // all the rest of the response from the server in in this byte slice so // we can reset the dbc.buf and reuse it to deserialize the serialized links dbc.buf.Reset() // ignoring error since doc says this method panics rather than return // non-nil error n, _ := dbc.buf.Write(linkEntryBytes) if n != len(linkEntryBytes) { return fmt.Errorf("Unexpected error when writing bytes to bytes.Buffer") } nrecs, err := rw.ReadInt(dbc.buf) if err != nil { return oerror.NewTrace(err) } var result interface{} nr := int(nrecs) // loop over all the serialized links for i := 0; i < nr; i++ { result, err = linkSerde.Deserialize(dbc.buf) if err != nil { return oerror.NewTrace(err) } linkBag.AddLink(result.(*oschema.OLink)) // FIXME: for some reason the server returns a serialized link // followed by an integer (so far always a 1 in my expts). // Not sure what to do with this int, so ignore for now intval, err := rw.ReadInt(dbc.buf) if err != nil { return oerror.NewTrace(err) } if intval != int32(1) { ogl.Warnf("DEBUG: Found a use case where the val pair of a link was not 1: %d\n", intval) } } return nil }
// // FetchRecordByRID takes an ORID and reads that record from the database. // NOTE: for now I'm assuming all records are Documents (they can also be "raw bytes" or "flat data") // and for some reason I don't understand, multiple records can be returned, so I'm returning // a slice of ODocument // // TODO: may also want to expose options: ignoreCache, loadTombstones bool // TODO: need to properly handle fetchPlan func FetchRecordByRID(dbc *DBClient, orid oschema.ORID, fetchPlan string) ([]*oschema.ODocument, error) { dbc.buf.Reset() err := writeCommandAndSessionId(dbc, REQUEST_RECORD_LOAD) if err != nil { return nil, oerror.NewTrace(err) } err = rw.WriteShort(dbc.buf, orid.ClusterID) if err != nil { return nil, oerror.NewTrace(err) } err = rw.WriteLong(dbc.buf, orid.ClusterPos) if err != nil { return nil, oerror.NewTrace(err) } err = rw.WriteString(dbc.buf, fetchPlan) if err != nil { return nil, oerror.NewTrace(err) } ignoreCache := true // hardcoding for now err = rw.WriteBool(dbc.buf, ignoreCache) if err != nil { return nil, oerror.NewTrace(err) } loadTombstones := false // hardcoding for now err = rw.WriteBool(dbc.buf, loadTombstones) if err != nil { return nil, oerror.NewTrace(err) } // send to the OrientDB server _, err = dbc.conx.Write(dbc.buf.Bytes()) if err != nil { return nil, oerror.NewTrace(err) } /* ---[ Read Response ]--- */ err = readStatusCodeAndSessionId(dbc) if err != nil { return nil, oerror.NewTrace(err) } // this query can return multiple records (though I don't understand why) // so must do this in a loop docs := make([]*oschema.ODocument, 0, 1) for { payloadStatus, err := rw.ReadByte(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } if payloadStatus == byte(0) { break } rectype, err := rw.ReadByte(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } recversion, err := rw.ReadInt(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } databytes, err := rw.ReadBytes(dbc.conx) if err != nil { return nil, oerror.NewTrace(err) } ogl.Debugf("rectype:%v, recversion:%v, len(databytes):%v\n", rectype, recversion, len(databytes)) if rectype == 'd' { // we don't know the classname so set empty value doc := oschema.NewDocument("") doc.RID = orid doc.Version = recversion // the first byte specifies record serialization version // use it to look up serializer serde := dbc.RecordSerDes[int(databytes[0])] // then strip off the version byte and send the data to the serde err = serde.Deserialize(dbc, doc, obuf.NewReadBuffer(databytes[1:])) if err != nil { return nil, fmt.Errorf("ERROR in Deserialize for rid %v: %v\n", orid, err) } docs = append(docs, doc) } else { return nil, fmt.Errorf("Only `document` records are currently supported by the client. Record returned was type: %v", rectype) } } return docs, nil }
// // OpenDatabase sends the REQUEST_DB_OPEN command to the OrientDB server to // open the db in read/write mode. The database name and type are required, plus // username and password. Database type should be one of the obinary constants: // DocumentDBType or GraphDBType. // func OpenDatabase(dbc *DBClient, dbname string, dbtype constants.DatabaseType, username, passw string) error { buf := dbc.buf buf.Reset() // first byte specifies request type err := rw.WriteByte(buf, REQUEST_DB_OPEN) if err != nil { return oerror.NewTrace(err) } // session-id - send a negative number to create a new server-side conx err = rw.WriteInt(buf, RequestNewSession) if err != nil { return oerror.NewTrace(err) } err = rw.WriteStrings(buf, DriverName, DriverVersion) if err != nil { return oerror.NewTrace(err) } err = rw.WriteShort(buf, dbc.binaryProtocolVersion) if err != nil { return oerror.NewTrace(err) } // dbclient id - send as null, but cannot be null if clustered config // TODO: change to use dbc.clusteredConfig once that is added err = rw.WriteNull(buf) if err != nil { return oerror.NewTrace(err) } // serialization-impl err = rw.WriteString(buf, dbc.serializationType) if err != nil { return oerror.NewTrace(err) } // token-session // TODO: hardcoded as false for now -> change later based on ClientOptions settings err = rw.WriteBool(buf, false) if err != nil { return oerror.NewTrace(err) } // dbname, dbtype, username, password err = rw.WriteStrings(buf, dbname, string(dbtype), username, passw) if err != nil { return oerror.NewTrace(err) } // now send to the OrientDB server _, err = dbc.conx.Write(buf.Bytes()) if err != nil { return oerror.NewTrace(err) } /* ---[ read back response ]--- */ // first byte indicates success/error status, err := rw.ReadByte(dbc.conx) if err != nil { return oerror.NewTrace(err) } dbc.currDB = NewDatabase(dbname, dbtype) // the first int returned is the session id sent - which was the `RequestNewSession` sentinel sessionValSent, err := rw.ReadInt(dbc.conx) if err != nil { return oerror.NewTrace(err) } if sessionValSent != RequestNewSession { return errors.New("Unexpected Error: Server did not return expected session-request-val that was sent") } // if status returned was ERROR, then the rest of server data is the exception info if status != RESPONSE_STATUS_OK { exceptions, err := rw.ReadErrorResponse(dbc.conx) if err != nil { return oerror.NewTrace(err) } return fmt.Errorf("Server Error(s): %v", exceptions) } // for the REQUEST_DB_OPEN case, another int is returned which is the new sessionId sessionId, err := rw.ReadInt(dbc.conx) if err != nil { return oerror.NewTrace(err) } dbc.sessionId = sessionId // next is the token, which may be null tokenBytes, err := rw.ReadBytes(dbc.conx) if err != nil { return oerror.NewTrace(err) } dbc.token = tokenBytes // array of cluster info in this db // TODO: do we need to retain all this in memory? numClusters, err := rw.ReadShort(dbc.conx) if err != nil { return oerror.NewTrace(err) } clusters := make([]OCluster, 0, numClusters) for i := 0; i < int(numClusters); i++ { clusterName, err := rw.ReadString(dbc.conx) if err != nil { return oerror.NewTrace(err) } clusterId, err := rw.ReadShort(dbc.conx) if err != nil { return oerror.NewTrace(err) } clusters = append(clusters, OCluster{Name: clusterName, Id: clusterId}) } dbc.currDB.Clusters = clusters // cluster-config - bytes - null unless running server in clustered config // TODO: treating this as an opaque blob for now clusterCfg, err := rw.ReadBytes(dbc.conx) if err != nil { return oerror.NewTrace(err) } dbc.currDB.ClustCfg = clusterCfg // orientdb server release - throwing away for now // TODO: need this? _, err = rw.ReadString(dbc.conx) if err != nil { return oerror.NewTrace(err) } // /* ---[ load #0:0 - config record ]--- */ schemaRIDStr, err := loadConfigRecord(dbc) if err != nil { return oerror.NewTrace(err) } clusterID, clusterPos, err := parseRid(schemaRIDStr) if err != nil { return oerror.NewTrace(err) } // /* ---[ load #0:1 - schema record ]--- */ err = loadSchema(dbc, oschema.ORID{ClusterID: clusterID, ClusterPos: clusterPos}) if err != nil { return oerror.NewTrace(err) } return nil }
// // loadConfigRecord loads record #0:0 for the current database, caching // some of the information returned into OStorageConfiguration // func loadConfigRecord(dbc *DBClient) (schemaRID string, err error) { // The config record comes back as type 'b' (raw bytes), which should // just be converted to a string then tokenized by the pipe char dbc.buf.Reset() var ( clusterId int16 clusterPos int64 ) err = writeCommandAndSessionId(dbc, REQUEST_RECORD_LOAD) if err != nil { return schemaRID, err } clusterId = 0 err = rw.WriteShort(dbc.buf, clusterId) if err != nil { return schemaRID, err } clusterPos = 0 err = rw.WriteLong(dbc.buf, clusterPos) if err != nil { return schemaRID, err } fetchPlan := "*:-1 index:0" err = rw.WriteString(dbc.buf, fetchPlan) if err != nil { return schemaRID, err } ignoreCache := true err = rw.WriteBool(dbc.buf, ignoreCache) if err != nil { return schemaRID, err } loadTombstones := true // based on Java client code err = rw.WriteBool(dbc.buf, loadTombstones) if err != nil { return schemaRID, err } // send to the OrientDB server _, err = dbc.conx.Write(dbc.buf.Bytes()) if err != nil { return schemaRID, err } /* ---[ Read Response ]--- */ err = readStatusCodeAndSessionId(dbc) if err != nil { return schemaRID, err } payloadStatus, err := rw.ReadByte(dbc.conx) if err != nil { return schemaRID, err } if payloadStatus == byte(0) { return schemaRID, errors.New("Payload status for #0:0 load was 0. No config data returned.") } rectype, err := rw.ReadByte(dbc.conx) if err != nil { return schemaRID, err } // this is the record version - don't see a reason to check or cache it right now _, err = rw.ReadInt(dbc.conx) if err != nil { return schemaRID, err } databytes, err := rw.ReadBytes(dbc.conx) if err != nil { return schemaRID, err } if rectype != 'b' { if err != nil { return schemaRID, fmt.Errorf("Expected rectype %d, but was: %d", 'b', rectype) } } payloadStatus, err = rw.ReadByte(dbc.conx) if err != nil { return schemaRID, err } if payloadStatus != byte(0) { return schemaRID, errors.New("Second Payload status for #0:0 load was not 0. More than one record returned unexpectedly") } err = parseConfigRecord(dbc.currDB, string(databytes)) if err != nil { return schemaRID, err } schemaRID = dbc.currDB.StorageCfg.schemaRID return schemaRID, err }
// // ConnectToServer logs into the OrientDB server with the appropriate // admin privileges in order to execute server-level commands (as opposed // to database-level commands). This must be called to establish a server // session before any other server-level commands. The username and password // required are for the server (admin) not any particular database. // func ConnectToServer(dbc *DBClient, adminUser, adminPassw string) error { buf := dbc.buf buf.Reset() // first byte specifies request type err := rw.WriteByte(buf, REQUEST_CONNECT) if err != nil { return err } // session-id - send a negative number to create a new server-side conx err = rw.WriteInt(buf, RequestNewSession) if err != nil { return err } err = rw.WriteStrings(buf, DriverName, DriverVersion) if err != nil { return err } err = rw.WriteShort(buf, dbc.binaryProtocolVersion) if err != nil { return err } // dbclient id - send as null, but cannot be null if clustered config // TODO: change to use dbc.clusteredConfig once that is added err = rw.WriteNull(buf) if err != nil { return err } // serialization-impl err = rw.WriteString(buf, dbc.serializationType) if err != nil { return err } // token-session // TODO: hardcoded as false for now -> change later based on ClientOptions settings err = rw.WriteBool(buf, false) if err != nil { return err } // admin username, password err = rw.WriteStrings(buf, adminUser, adminPassw) if err != nil { return err } // send to OrientDB server _, err = dbc.conx.Write(buf.Bytes()) if err != nil { return err } /* ---[ Read Server Response ]--- */ // first byte indicates success/error status, err := rw.ReadByte(dbc.conx) if err != nil { return err } // the first int returned is the session id sent - which was the `RequestNewSession` sentinel sessionValSent, err := rw.ReadInt(dbc.conx) if err != nil { return err } if sessionValSent != RequestNewSession { return errors.New("Unexpected Error: Server did not return expected session-request-val that was sent") } // if status returned was ERROR, then the rest of server data is the exception info if status != RESPONSE_STATUS_OK { exceptions, err := rw.ReadErrorResponse(dbc.conx) if err != nil { return err } return fmt.Errorf("Server Error(s): %v", exceptions) } // for the REQUEST_CONNECT case, another int is returned which is the new sessionId sessionId, err := rw.ReadInt(dbc.conx) if err != nil { return err } // TODO: this assumes you can only have one sessionId - but perhaps can have a server sessionid // and one or more database sessions open at the same time ????? dbc.sessionId = sessionId tokenBytes, err := rw.ReadBytes(dbc.conx) if err != nil { return err } dbc.token = tokenBytes return nil }
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 }