private ODocument parseDocument(BinaryReader reader, ODocument document)
        {
            List<FieldDefinition> fd = new List<FieldDefinition>();
            var prop = String.Empty;

            while (true)
            {
                int len = readAsInteger(reader);
                if (len == 0)
                    break;

                if (len > 0)
                {
                    prop = Encoding.UTF8.GetString(reader.ReadBytesRequired(len));
                    int valuePos = reader.ReadInt32EndianAware();
                    OType valuetype = (OType)reader.ReadByte();
                    fd.Add(new FieldDefinition { FieldName = prop, Pointer = valuePos, DataType = valuetype });
                }
                else
                {
                    //TODO: Implement schema aware read
                    var propid = (len * -1) - 1;
                    prop = "no_schema";
                    int valuePos = reader.ReadInt32EndianAware();
                    fd.Add(new FieldDefinition { FieldName = prop, Pointer = valuePos, DataType = OType.Date });
                }
            }

            foreach (var f in fd)
            {
                if (f.Pointer != 0)
                {
                    readOType(reader, f.FieldName, document, f.DataType);
                }
                else
                {
                    document[f.FieldName] = null;
                }
            }

            return document;
        }
        internal byte[] ReadToken(BinaryReader reader)
        {
            var size = reader.ReadInt32EndianAware();
            var token = reader.ReadBytesRequired(size);
            
            // if token renewed
            if (token.Length > 0)
                _database.GetConnection().Token = token;

            return token;
        }
        private ODocument ParseDocument(BinaryReader reader)
        {
            ODocument document = null;

            short classId = reader.ReadInt16EndianAware();

            if (classId == -2) // NULL
            {
            }
            else if (classId == -3) // record id
            {
                ORID orid = new ORID();
                orid.ClusterId = reader.ReadInt16EndianAware();
                orid.ClusterPosition = reader.ReadInt64EndianAware();

                document = new ODocument();
                document.ORID = orid;
                document.OClassId = classId;
            }
            else
            {
                ORecordType type = (ORecordType)reader.ReadByte();

                ORID orid = new ORID();
                orid.ClusterId = reader.ReadInt16EndianAware();
                orid.ClusterPosition = reader.ReadInt64EndianAware();
                int version = reader.ReadInt32EndianAware();
                int recordLength = reader.ReadInt32EndianAware();
                byte[] rawRecord = reader.ReadBytes(recordLength);

                document = new ODocument { ORID = orid, OVersion = version, OType = ORecordType.Document, OClassId = classId };

                document = Serializer.Deserialize(rawRecord, document);

            }

            return document;
        }
        //public static int IntParseFast(string value)
        //{
        //    int result = 0;
        //    for (int i = 0; i < value.Length; i++)
        //    {
        //        char letter = value[i];
        //        result = 10 * result + (letter - 48);
        //    }
        //    return result;
        //}

        /// <summary>
        /// Parse RidBags ex. %[content:binary]; where [content:binary] is the actual binary base64 content.
        /// </summary>
        /// <param name="i"></param>
        /// <param name="recordString"></param>
        /// <param name="document"></param>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        private static int ParseRidBags(int i, string recordString, ODocument document, string fieldName)
        {
            //move to first base64 char
            i++;

            StringBuilder builder = new StringBuilder();

            while (recordString[i] != ';')
            {
                builder.Append(recordString[i]);
                i++;
            }

            // use a list as it preserves order at this stage which may be important when using ordered edges
            var rids = new List<ORID>();

            var value = Convert.FromBase64String(builder.ToString());
            using (var stream = new MemoryStream(value))
            using (var reader = new BinaryReader(stream))
            {
                var first = reader.ReadByte();
                int offset = 1;
                if ((first & 2) == 2)
                {
                    // uuid parsing is not implemented
                    offset += 16;
                }

                if ((first & 1) == 1) // 1 - embedded,0 - tree-based 
                {
                    var entriesSize = reader.ReadInt32EndianAware();
                    for (int j = 0; j < entriesSize; j++)
                    {
                        var clusterid = reader.ReadInt16EndianAware();
                        var clusterposition = reader.ReadInt64EndianAware();
                        rids.Add(new ORID(clusterid, clusterposition));
                    }
                }
                else
                {
                    throw new NotImplementedException("tree based ridbag");
                }
            }

            document[fieldName] = rids;
            //move past ';'
            i++;

            return i;
        }
        private void ReadAssociatedResult(BinaryReader reader)
        {
            var zero = reader.ReadInt16EndianAware();
            if (zero != 0)
                throw new InvalidOperationException("Unsupported record format");

            ORecordType recordType = (ORecordType)reader.ReadByte();
            if (recordType != ORecordType.Document)
                throw new InvalidOperationException("Unsupported record type");

            short clusterId = reader.ReadInt16EndianAware();
            long clusterPosition = reader.ReadInt64EndianAware();
            int recordVersion = reader.ReadInt32EndianAware();

            var recordLength = reader.ReadInt32EndianAware();
            var record = reader.ReadBytes(recordLength);

            //var document = RecordCSVSerializer.Deserialize(new ORID(clusterId, clusterPosition), recordVersion, ORecordType.Document, 0, record);
            var document = Serializer
                .Deserialize(record, new ODocument { ORID = new ORID(clusterId, clusterPosition), OVersion = recordVersion, OType = ORecordType.Document });

            _database.ClientCache[document.ORID] = document;
        }
        private void ReadPrimaryResult(ODocument responseDocument, BinaryReader reader)
        {
            responseDocument.SetField("PayloadStatus", PayloadStatus.SingleRecord);
            int contentLength;
            byte[] readBytes;
            int version;
            ORecordType recordType;

            if (OClient.ProtocolVersion < 28)
            {
                contentLength = reader.ReadInt32EndianAware();
                readBytes = reader.ReadBytes(contentLength);
                version = reader.ReadInt32EndianAware();
                recordType = (ORecordType)reader.ReadByte();
            }
            else
            {
                recordType = (ORecordType)reader.ReadByte();
                version = reader.ReadInt32EndianAware();
                contentLength = reader.ReadInt32EndianAware();
                readBytes = reader.ReadBytes(contentLength);
            }

            var document = new ODocument();

            switch (recordType)
            {
                case ORecordType.Document:
                    document = Serializer.Deserialize(readBytes, new ODocument());
                    document.ORID = _orid;
                    document.OVersion = version;
                    responseDocument.SetField("Content", document);
                    break;
                case ORecordType.RawBytes:
                    document.SetField("RawBytes", readBytes);
                    responseDocument.SetField("Content", document);
                    break;
                case ORecordType.FlatData:
                    break;
            }
        }
        private void readOType(BinaryReader reader, string fieldName, ODocument document, OType type)
        {
            switch (type)
            {
                case OType.Integer:
                    document.SetField<int>(fieldName, readAsInteger(reader));
                    break;
                case OType.Long:
                    document.SetField<long>(fieldName, readAsLong(reader));
                    break;
                case OType.Short:
                    document.SetField<short>(fieldName, readAsShort(reader));
                    break;
                case OType.String:
                    document.SetField<string>(fieldName, readString(reader));
                    break;
                case OType.Double:
                    document.SetField<double>(fieldName, BitConverter.Int64BitsToDouble(readLong(reader)));
                    break;
                case OType.Float:
                    document.SetField<float>(fieldName, readFloat(reader));
                    break;
                case OType.Decimal:
                    var scale = reader.ReadInt32EndianAware();

                    var valueSize = reader.ReadInt32EndianAware();

                    // read Fine the value
                    var valuex = reader.ReadBytesRequired(valueSize);

                    Int64 x1 = 0;

                    if ((valuex[0] & 0x80) == 0x80)
                        x1 = (sbyte)valuex[0];
                    else
                        x1 = valuex[0];

                    for (int i = 1; i < valuex.Length; i++)
                    {
                        x1 = (x1 << 8) | valuex[i];
                    }

                    try
                    {
                        document.SetField(fieldName, new Decimal(x1 * Math.Pow(10, (-1) * scale)));
                    }
                    catch (OverflowException)
                    {
                        document.SetField(fieldName, x1 * Math.Pow(10, (-1) * scale));
                    }
                    break;
                case OType.Byte:
                    document.SetField<byte>(fieldName, reader.ReadByte());
                    break;
                case OType.Boolean:
                    document.SetField<bool>(fieldName, reader.ReadByte() == 1 ? true : false);
                    break;
                case OType.DateTime:
                    document.SetField<DateTime>(fieldName, readDateTime(reader));
                    break;
                case OType.Date:
                    document.SetField<DateTime>(fieldName, readDate(reader));
                    break;
                case OType.EmbeddedList:
                    var listLength = readAsInteger(reader);
                    OType embeddedListRecorType = (OType)reader.ReadByte();
                    List<Object> embeddedList = new List<Object>();
                    for (int i = 0; i < listLength; i++)
                    {
                        var d = new ODocument();
                        OType dataType = (OType)reader.ReadByte();
                        readOType(reader, i.ToString(), d, dataType);
                        embeddedList.AddRange(d.Values);
                    }
                    document.SetField(fieldName, embeddedList);
                    break;
                case OType.EmbeddedSet:
                    var embeddedSetLen = readAsInteger(reader);
                    OType embeddedSetRecorType = (OType)reader.ReadByte();
                    HashSet<ODocument> embeddedSet = new HashSet<ODocument>();
                    for (int i = 0; i < embeddedSetLen; i++)
                    {
                        var d = new ODocument();
                        OType dataType = (OType)reader.ReadByte();
                        readOType(reader, "", d, dataType);
                        embeddedSet.Add(d);
                    }
                    document.SetField(fieldName, embeddedSet);
                    break;
                case OType.EmbeddedMap:
                    /* 
                     * header:headerStructure | values:valueStructure
                     * headerStructure
                     * ===============
                     * keyType:byte | keyValue:byte[]
                     * 
                     * valueStructure
                     * ==============
                     * valueType:byte | value:byte[]
                    */
                    var size = readAsInteger(reader);

                    var fd = new FieldDefinition[size];
                    Dictionary<string, Object> map = new Dictionary<string, object>();
                    for (int i = 0; i < size; i++)
                    {
                        fd[i] = new FieldDefinition();

                        var d = new ODocument();
                        var keyType = (OType)reader.ReadByte();
                        if (keyType != OType.String)
                            throw new NotImplementedException("key type " + keyType + " not implemented for EmbededMap");
                        readOType(reader, "key", d, keyType);

                        fd[i].FieldName = d.GetField<string>("key");
                        fd[i].Pointer = reader.ReadInt32EndianAware();
                        fd[i].DataType = (OType)reader.ReadByte();
                    }
                    for (int i = 0; i < size; i++)
                    {
                        var d = new ODocument();
                        if (fd[i].Pointer > 0)
                        {
                            readOType(reader, "value", d, fd[i].DataType);
                            map.Add(fd[i].FieldName, d.GetField<object>("value"));
                        }
                        else
                        {
                            map.Add(fd[i].FieldName, null);
                        }
                    }
                    document.SetField<Dictionary<string, Object>>(fieldName, map);
                    break;
                case OType.Embedded:
                    var version = reader.ReadByte();
                    parseDocument(reader, document);
                    break;
                case OType.Link:
                    var claster = readAsLong(reader);
                    var record = readAsLong(reader);
                    document.SetField(fieldName, new ORID((short)claster, record));
                    break;
                case OType.LinkBag:
                    var rids = new HashSet<ORID>();
                    var config = reader.ReadByte();
                    if ((config & 2) == 2)
                    {
                        // uuid parsing is not implemented
                        config += 16;
                    }

                    if ((config & 1) == 1) // 1 - embedded,0 - tree-based 
                    {
                        var entriesSize = reader.ReadInt32EndianAware();
                        for (int j = 0; j < entriesSize; j++)
                        {
                            var clusterid = reader.ReadInt16EndianAware();
                            var clusterposition = reader.ReadInt64EndianAware();
                            rids.Add(new ORID(clusterid, clusterposition));
                        }
                    }
                    else
                    {
                        throw new NotImplementedException("tree based ridbag");
                    }
                    document.SetField(fieldName, rids);
                    break;
                case OType.LinkList:
                    var linkList = readLinkCollection(reader);
                    document.SetField(fieldName, linkList);
                    break;
                case OType.LinkSet:
                    var linkSet = new HashSet<ORID>(readLinkCollection(reader));
                    document.SetField(fieldName, linkSet);
                    break;
                case OType.Any:
                    break;
                default:
                    throw new OException(OExceptionType.Deserialization, "The field type: " + type.ToString() + "not implemented");
            }
        }
        //public  int IntParseFast(string value)
        //{
        //    int result = 0;
        //    for (int i = 0; i < value.Length; i++)
        //    {
        //        char letter = value[i];
        //        result = 10 * result + (letter - 48);
        //    }
        //    return result;
        //}

        /// <summary>
        /// Parse RidBags ex. %[content:binary]; where [content:binary] is the actual binary base64 content.
        /// </summary>
        /// <param name="i"></param>
        /// <param name="recordString"></param>
        /// <param name="document"></param>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        private int ParseRidBags(int i, string recordString, ODocument document, string fieldName)
        {
            //move to first base64 char
            i++;

            StringBuilder builder = new StringBuilder();

            while (recordString[i] != ';')
            {
                builder.Append(recordString[i]);
                i++;
            }

            // use a list as it preserves order at this stage which may be important when using ordered edges
            var rids = new List<ORID>();

            var value = Convert.FromBase64String(builder.ToString());
            using (var stream = new MemoryStream(value))
            using (var reader = new BinaryReader(stream))
            {
                var first = reader.ReadByte();
                int offset = 1;
                if ((first & 2) == 2)
                {
                    // uuid parsing is not implemented
                    offset += 16;
                }

                if ((first & 1) == 1) // 1 - embedded,0 - tree-based 
                {
                    var entriesSize = reader.ReadInt32EndianAware();
                    for (int j = 0; j < entriesSize; j++)
                    {
                        var clusterid = reader.ReadInt16EndianAware();
                        var clusterposition = reader.ReadInt64EndianAware();
                        rids.Add(new ORID(clusterid, clusterposition));
                    }
                }
                else
                {
                    // Maybe not parse this type of Field and only then Requested retrieve ?
                    // Lazy loading

                    if (_connection == null || !_connection.IsActive)
                        throw new OException(OExceptionType.Connection, "Connection is not opened or is null");

                    // Tree based RidBag - (collectionPointer)(size:int)(changes)

                    // Collection Pointer - (fileId:long)(pageIndex:long)(pageOffset:int)
                    var fileId = reader.ReadInt64EndianAware();
                    var pageIndex = reader.ReadInt64EndianAware();
                    var pageOffset = reader.ReadInt32EndianAware();

                    // size
                    var size = reader.ReadInt32EndianAware();

                    //only process ridbag if size > 0, otherwise the call to SBTreeBonsaiFirstKey operation makes the connection crash (the server probably isn't expecting this use case)
                    if (size > 0)
                    {
                        // Changes - (changesSize:int)[(link:rid)(changeType:byte)(value:int)]*
                        var changesSize = reader.ReadInt32EndianAware();
                        if (changesSize > 0)
                        //for (int j = 0; j < changesSize; j++)
                        {
                            throw new NotImplementedException("RidBag Changes not yet implemented");
                        }

                        var operation = new SBTreeBonsaiFirstKey(null);
                        operation.FileId = fileId;
                        operation.PageIndex = pageIndex;
                        operation.PageOffset = pageOffset;


                        // Not realy quiete about this
                        var connection = OClient.ReleaseConnection(_connection.Alias);

                        var entries = new Dictionary<ORID, int>();
                        try
                        {
                            var orid = connection.ExecuteOperation(operation);
                            var ft = true;
                            var key = orid.GetField<ORID>("rid");
                            do
                            {
                                var op = new SBTreeBonsaiGetEntriesMajor(null);
                                op.FileId = fileId;
                                op.PageIndex = pageIndex;
                                op.PageOffset = pageOffset;
                                op.FirstKey = key;
                                op.Inclusive = ft;

                                var res = connection.ExecuteOperation(op);
                                entries = res.GetField<Dictionary<ORID, int>>("entries");

                                rids.AddRange(entries.Keys);

                                if (entries.Count == 0)
                                    break;

                                key = entries.Last().Key;
                                ft = false;

                            } while (true);
                        }
                        finally
                        {
                            OClient.ReturnConnection(connection);
                        }
                    }
                }
            }

            document[fieldName] = rids;
            //move past ';'
            i++;

            return i;
        }
        private int ParseRidBags(int i, byte[] serializedRecord, out object result)
        {
            i++;
            var startIndex = i;
            StringBuilder builder = new StringBuilder();

            while (serializedRecord[i] != SEMI_COLON)
            {
                i++;
            }
            var value = Convert.FromBase64String(ToString(startIndex, i, serializedRecord));
            List<ORID> rids = new List<ORID>();
            using (var ms = new MemoryStream(value))
            {
                using (var br = new BinaryReader(ms))
                {
                    var first = br.ReadByte();
                    int offset = 1;
                    startIndex++;

                    if ((first & 2) == 2)
                    {
                        // uuid parsing is not implemented
                        offset += 16;
                    }

                    if ((first & 1) == 1)
                    {
                        var entriesSize = br.ReadInt32EndianAware();
                        for (int j = 0; j < entriesSize; j++)
                        {
                            var clusterid = br.ReadInt16EndianAware();
                            var clusterposition = br.ReadInt64EndianAware();
                            rids.Add(new ORID(clusterid, clusterposition));
                        }
                    }
                    else throw new NotImplementedException("Tree-based RID Bags are not supported.");
                }
            }

            result = rids;

            i++;
            return i;
        }
Beispiel #10
0
        private void ReadPrimaryResult(ODocument responseDocument, BinaryReader reader)
        {
            responseDocument.SetField("PayloadStatus", PayloadStatus.SingleRecord);

            var contentLength = reader.ReadInt32EndianAware();
            byte[] readBytes = reader.ReadBytes(contentLength);
            var version = reader.ReadInt32EndianAware();
            var recordType = (ORecordType)reader.ReadByte();

            var document = new ODocument();

            switch (recordType)
            {
                case ORecordType.Document:
                    string serialized = System.Text.Encoding.Default.GetString(readBytes);
                    document = RecordSerializer.Deserialize(serialized);
                    document.ORID = _orid;
                    document.OVersion = version;
                    responseDocument.SetField("Content", document);
                    break;
                case ORecordType.RawBytes:
                    document.SetField("RawBytes", readBytes);
                    responseDocument.SetField("Content", document);
                    break;
                case ORecordType.FlatData:
                    break;
            }
        }