Пример #1
0
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
}
Пример #2
0
//
// DatabaseExists is a server-level command, so must be preceded by calling
// ConnectToServer, otherwise an authorization error will be returned.
// The storageType param must be either PersistentStorageType or VolatileStorageType.
//
func DatabaseExists(dbc *DBClient, dbname string, storageType constants.StorageType) (bool, error) {
	dbc.buf.Reset()

	if dbc.sessionId == NoSessionID {
		return false, oerror.SessionNotInitialized{}
	}

	// cmd
	err := rw.WriteByte(dbc.buf, REQUEST_DB_EXIST)
	if err != nil {
		return false, err
	}

	// session id
	err = rw.WriteInt(dbc.buf, dbc.sessionId)
	if err != nil {
		return false, err
	}

	// database name, storage-type
	err = rw.WriteStrings(dbc.buf, dbname, string(storageType))
	if err != nil {
		return false, err
	}

	// send to the OrientDB server
	_, err = dbc.conx.Write(dbc.buf.Bytes())
	if err != nil {
		return false, err
	}

	/* ---[ Read Response From Server ]--- */

	status, err := rw.ReadByte(dbc.conx)
	if err != nil {
		return false, err
	}

	err = readAndValidateSessionId(dbc.conx, dbc.sessionId)
	if err != nil {
		return false, err
	}

	if status == RESPONSE_STATUS_ERROR {
		serverExceptions, err := rw.ReadErrorResponse(dbc.conx)
		if err != nil {
			return false, err
		}
		return false, fmt.Errorf("Server Error(s): %v", serverExceptions)
	}

	// the answer to the query
	dbexists, err := rw.ReadBool(dbc.conx)
	if err != nil {
		return false, err
	}

	return dbexists, nil
}
Пример #3
0
//
// CreateDatabase will create a `remote` database of the type and storageType specified.
// dbType must be type DocumentDBType or GraphDBType.
// storageType must type PersistentStorageType or VolatileStorageType.
//
func CreateDatabase(dbc *DBClient, dbname string, dbtype constants.DatabaseType, storageType constants.StorageType) error {
	dbc.buf.Reset()

	/* ---[ precondition checks ]--- */

	// TODO: may need to change this to serverSessionid (can the "sessionId" be used for both server connections and db conx?)
	if dbc.sessionId == NoSessionID {
		return oerror.SessionNotInitialized{}
	}

	/* ---[ build request and send to server ]--- */

	// cmd
	err := rw.WriteByte(dbc.buf, REQUEST_DB_CREATE)
	if err != nil {
		return err
	}

	// session id
	err = rw.WriteInt(dbc.buf, dbc.sessionId)
	if err != nil {
		return err
	}

	err = rw.WriteStrings(dbc.buf, dbname, string(dbtype), string(storageType))
	if err != nil {
		return err
	}

	// send to the OrientDB server
	_, err = dbc.conx.Write(dbc.buf.Bytes())
	if err != nil {
		return err
	}

	/* ---[ read response from server ]--- */

	status, err := rw.ReadByte(dbc.conx)
	if err != nil {
		return err
	}

	err = readAndValidateSessionId(dbc.conx, dbc.sessionId)
	if err != nil {
		return err
	}

	if status == RESPONSE_STATUS_ERROR {
		serverExceptions, err := rw.ReadErrorResponse(dbc.conx)
		if err != nil {
			return err
		}
		return fmt.Errorf("Server Error(s): %v", serverExceptions)
	}

	return nil
}
Пример #4
0
//
// DropDatabase drops the specified database. The caller must provide
// both the name and the type of the database.  The type should either:
//
//     obinary.DocumentDBType
//     obinary.GraphDBType
//
// This is a "server" command, so you must have already called
// ConnectToServer before calling this function.
//
func DropDatabase(dbc *DBClient, dbname string, dbtype constants.DatabaseType) error {
	dbc.buf.Reset()

	if dbc.sessionId == NoSessionID {
		return oerror.SessionNotInitialized{}
	}

	// cmd
	err := rw.WriteByte(dbc.buf, REQUEST_DB_DROP)
	if err != nil {
		return err
	}

	// session id
	err = rw.WriteInt(dbc.buf, dbc.sessionId)
	if err != nil {
		return err
	}

	// database name, storage-type
	err = rw.WriteStrings(dbc.buf, dbname, string(dbtype))
	if err != nil {
		return err
	}

	// send to the OrientDB server
	_, err = dbc.conx.Write(dbc.buf.Bytes())
	if err != nil {
		return err
	}

	/* ---[ read response from server ]--- */

	status, err := rw.ReadByte(dbc.conx)
	if err != nil {
		return err
	}

	err = readAndValidateSessionId(dbc.conx, dbc.sessionId)
	if err != nil {
		return err
	}

	if status == RESPONSE_STATUS_ERROR {
		serverExceptions, err := rw.ReadErrorResponse(dbc.conx)
		if err != nil {
			return err
		}
		return fmt.Errorf("Server Error(s): %v", serverExceptions)
	}

	return nil
}
Пример #5
0
//
// 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
}
Пример #6
0
//
// RequestDBList works like the "list databases" command from the OrientDB client.
// The result is put into a map, where the key of the map is the name of the
// database and the value is the type concatenated with the path, like so:
//
//     key:  cars
//     val:  plocal:/path/to/orientdb-community-2.0.1/databases/cars
//
func RequestDBList(dbc *DBClient) (map[string]string, error) {
	dbc.buf.Reset()

	if dbc.sessionId == NoSessionID {
		return nil, oerror.SessionNotInitialized{}
	}

	// cmd
	err := rw.WriteByte(dbc.buf, REQUEST_DB_LIST)
	if err != nil {
		return nil, oerror.NewTrace(err)
	}

	// session id
	err = rw.WriteInt(dbc.buf, dbc.sessionId)
	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)
	}

	status, err := rw.ReadByte(dbc.conx)
	if err != nil {
		return nil, oerror.NewTrace(err)
	}

	err = readAndValidateSessionId(dbc.conx, dbc.sessionId)
	if err != nil {
		return nil, oerror.NewTrace(err)
	}

	if status == RESPONSE_STATUS_ERROR {
		serverExceptions, err := rw.ReadErrorResponse(dbc.conx)
		if err != nil {
			return nil, oerror.NewTrace(err)
		}
		return nil, fmt.Errorf("Server Error(s): %v", serverExceptions)
	}

	// the bytes returned as a serialized EMBEDDEDMAP, so send it to the SerDe
	responseBytes, err := rw.ReadBytes(dbc.conx)
	if err != nil {
		return nil, oerror.NewTrace(err)
	}

	serde := dbc.RecordSerDes[int(responseBytes[0])]
	buf := obuf.NewReadBuffer(responseBytes[1:])
	doc := oschema.NewDocument("")
	err = serde.Deserialize(dbc, doc, buf)
	if err != nil {
		return nil, oerror.NewTrace(err)
	}

	m := make(map[string]string)
	fldMap := doc.GetField("databases").Value.(map[string]interface{})
	for k, v := range fldMap {
		m[k] = v.(string)
	}

	return m, nil
}
Пример #7
0
//
// 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
}