예제 #1
0
        public DateTimeOffset?GetTimestamp(int columnIndex, int rowIndex)
        {
            this.CheckColumn(columnIndex, ColumnType.Timestamp, null);

            // Timestamp カラムは、まず配列がある
            var topArray = new RealmArray(this.Ref.NewRef((ulong)this.Columns[this.GetColumnBpTreeIndex(columnIndex)]));

            // 配列の要素は、秒とナノ秒
            var secondsBpTree     = new BpTree(this.Ref.NewRef((ulong)topArray[0]));
            var nanosecondsBpTree = new BpTree(this.Ref.NewRef((ulong)topArray[1]));

            // 秒を取得
            var(leaf, indexInLeaf) = secondsBpTree.Get(rowIndex);
            var seconds = new RealmArrayIntNull(leaf)[indexInLeaf];

            // seconds が null ならば、返すべき値は null
            if (!seconds.HasValue)
            {
                return(null);
            }

            // ナノ秒を取得
            (leaf, indexInLeaf) = nanosecondsBpTree.Get(rowIndex);
            var nanoseconds = new RealmArray(leaf)[indexInLeaf];

            // 参考: 秒とナノ秒で正負混ぜることはできない
            // https://github.com/realm/realm-core/blob/v5.12.7/src/realm/timestamp.hpp#L43-L63

            // DateTimeOffset が表せるのは 100ns
            return(DateTimeOffset.UnixEpoch
                   .AddTicks(seconds.Value * TimeSpan.TicksPerSecond + nanoseconds / 100));
        }
예제 #2
0
        /// <summary>
        /// 最上位のテーブルを <paramref name="ref"/> から作成
        /// </summary>
        public RealmTable(ReferenceAccessor @ref)
        {
            this.Ref = @ref;

            var tableArray = new RealmArray(@ref);

            this.Spec    = new TableSpec(@ref.NewRef((ulong)tableArray[0]));
            this.Columns = new RealmArray(@ref.NewRef((ulong)tableArray[1]));
        }
예제 #3
0
        static void Main(string[] args)
        {
            var fileName = args.Length > 0 ? args[0] : "default.realm";

            using (var mmf = MemoryMappedFile.CreateFromFile(fileName, FileMode.Open, null, 0, MemoryMappedFileAccess.Read))
                using (var accessor = mmf.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read))
                {
                    var header = RealmFileHeader.ReadFrom(accessor);

                    Console.WriteLine("File Format Version: {0}", header.GetTopRef().FileFormatVersion);

                    // ファイル内では、 ref の値はそのまま使える(追加でアロケーションすると話は別)
                    var topArray = new RealmArray(new ReferenceAccessor(accessor, header.GetTopRef().Ref));

                    Console.WriteLine("Top Array Count: {0}", topArray.Count);

                    // HasRefs な Array に数値が入っているので、最下位ビットが 1 になっている
                    // ビットシフトで元の値が手に入る
                    Console.WriteLine("Logical File Size: {0}", (ulong)topArray[2] >> 1);

                    // 配列の 1 番目がテーブル名リスト
                    var tableNameArray = new RealmArrayString(new ReferenceAccessor(accessor, (ulong)topArray[0]), false);

                    // 2 番目がテーブルのリスト
                    var tableArray = new RealmArray(new ReferenceAccessor(accessor, (ulong)topArray[1]));

                    Console.WriteLine();
                    Console.WriteLine("Tables");
                    for (var i = 0; i < tableNameArray.Count; i++)
                    {
                        var table = new RealmTable(new ReferenceAccessor(accessor, (ulong)tableArray[i]));
                        Console.WriteLine(" - {0} (Count: {1})", tableNameArray[i], table.RowCount);
                        PrintTableSpec(table.Spec, tableNameArray, GetBacklinkTarget, 2);
                    }

                    Console.WriteLine();
                    Console.WriteLine("Contents");
                    for (var i = 0; i < tableNameArray.Count; i++)
                    {
                        var table = new RealmTable(new ReferenceAccessor(accessor, (ulong)tableArray[i]));
                        Console.WriteLine(" - {0} ({1}/{2})", tableNameArray[i], Math.Min(table.RowCount, PrintCount), table.RowCount);
                        PrintTableContent(table, GetBacklinkTarget, 2);
                    }

                    string GetBacklinkTarget(int tableIndex, int columnIndex)
                    {
                        var targetTable      = new RealmTable(tableArray.Ref.NewRef((ulong)tableArray[tableIndex]));
                        var targetColumnName = targetTable.Spec.GetColumn(columnIndex).Name;

                        return(tableNameArray[tableIndex] + "." + targetColumnName);
                    }

                    Debugger.Break();
                }
        }
예제 #4
0
        public DateTimeOffset GetOldDateTime(int columnIndex, int rowIndex)
        {
            this.CheckColumn(columnIndex, ColumnType.OldDateTime, false);

            var(leaf, indexInLeaf) = this.GetFromBpTree(columnIndex, rowIndex);
            var seconds = new RealmArray(leaf)[indexInLeaf];

            // 1970/01/01 00:00:00 UTC からの秒数で保存されている
            // https://github.com/realm/realm-core/blob/v5.12.2/src/realm/olddatetime.hpp#L35-L36
            return(DateTimeOffset.FromUnixTimeSeconds(seconds));
        }
예제 #5
0
        private (ReferenceAccessor childRef, int indexInChild) FindChild(RealmArray innerNode, int index)
        {
            // https://github.com/realm/realm-core/blob/v5.12.1/src/realm/bptree.cpp#L69-L113
            // Compact Form と General Form: https://github.com/realm/realm-core/blob/v5.12.1/src/realm/array.cpp#L91-L139

            int childIndex, indexInChild;

            var firstValue = innerNode[0];

            if (firstValue % 2 != 0)
            {
                // Compact Form
                // invar:bptree-node-form により、子孫ノードはすべて Compact Form であることがわかっているので
                // elemsPerChild からインデックスを計算できる

                // firstValue = 1 + 2 * elems_per_child
                var elemsPerChild = checked ((int)(firstValue / 2));

                childIndex   = index / elemsPerChild;
                indexInChild = index % elemsPerChild;
            }
            else
            {
                // General Form
                // firstValue は offset 配列への参照(参照なので最下位ビットは 0 になり、この if が成立)

                // offsetArray の i 番目の要素は i+1 の子までに何個の子要素が含まれているか
                // このノードの子ノードが 1 つしかないならば、 offsetArray は 0 件
                var offsetArray = new RealmArray(this.Ref.NewRef((ulong)firstValue));

                // 何番目の子ノードに index が含まれているかを探す
                childIndex = 0;
                for (; childIndex < offsetArray.Count; childIndex++)
                {
                    if (offsetArray[childIndex] > index)
                    {
                        break;
                    }
                }

                // childIndex - 1 までの子ノードに何個の要素が含まれているかを求める
                var elemIndexOffset = childIndex == 0
                    ? 0
                    : checked ((int)offsetArray[childIndex - 1]);

                indexInChild = index - elemIndexOffset;
            }

            // innerNode の最初の要素を飛ばすので、 +1
            return(this.Ref.NewRef((ulong)innerNode[1 + childIndex]), indexInChild);
        }
예제 #6
0
        // mixed カラムはバインディングからは作成されない?
        // https://github.com/realm/realm-object-store/blob/53b6e0e47d681d5b358c1a42c80191a9153bac9e/src/object_store.cpp#L95

        /// <returns>行インデックス</returns>
        public int?GetLink(int columnIndex, int rowIndex)
        {
            this.CheckColumn(columnIndex, ColumnType.Link, true);

            // Integer カラムとして読み出す
            var(leaf, indexInLeaf) = this.GetFromBpTree(columnIndex, rowIndex);
            var value = new RealmArray(leaf)[indexInLeaf];

            if (value == 0)
            {
                return(null);
            }

            // 0 を null に使っているので、記録されている値は 1 足されている
            return(checked ((int)(value - 1)));
        }
예제 #7
0
        public RealmArrayBinary(ReferenceAccessor @ref)
        {
            var array = new RealmArray(@ref);

            this._array = array;

            this._offsets = new RealmArray(@ref.NewRef((ulong)array[0]));

            // ArrayBlob なので一応 Array のヘッダーを持っている
            this._blob = @ref.NewRef((ulong)array[1] + RealmArrayHeader.HeaderSize);

            // 旧バージョンでは nulls がなかった
            if (array.Count >= 3)
            {
                this._nulls = new RealmArray(@ref.NewRef((ulong)array[2]));
            }
        }
        public RealmArrayStringLong(ReferenceAccessor @ref, bool nullable)
        {
            this.Nullable = nullable;

            var array = new RealmArray(@ref);

            this._array = array;

            this._offsets = new RealmArray(@ref.NewRef((ulong)array[0]));

            // ArrayBlob なので一応 Array のヘッダーを持っている
            this._blob = @ref.NewRef((ulong)array[1] + RealmArrayHeader.HeaderSize);

            if (nullable)
            {
                this._nulls = new RealmArray(@ref.NewRef((ulong)array[2]));
            }
        }
예제 #9
0
        public TableSpec(ReferenceAccessor @ref)
        {
            this.Ref = @ref;

            var specArray = new RealmArray(@ref);

            this._types = new RealmArray(@ref.NewRef((ulong)specArray[0]));
            this._names = new RealmArrayString(@ref.NewRef((ulong)specArray[1]), false);
            this._attr  = new RealmArray(@ref.NewRef((ulong)specArray[2]));

            if (specArray.Count >= 4)
            {
                var subspecsRef = (ulong)specArray[3];
                if (subspecsRef != 0)
                {
                    this._subspecs = new RealmArray(@ref.NewRef(subspecsRef));
                }
            }
        }
 public RealmArrayBigBlobs(ReferenceAccessor @ref)
 {
     this._array = new RealmArray(@ref);
 }
예제 #11
0
 public BpTree(ReferenceAccessor @ref)
 {
     this.Ref   = @ref;
     this._root = new RealmArray(@ref);
 }
 public RealmArrayIntNull(ReferenceAccessor @ref)
 {
     this._array = new RealmArray(@ref);
 }
예제 #13
0
 /// <summary>
 /// サブテーブル
 /// </summary>
 public RealmTable(TableSpec spec, RealmArray columns)
 {
     this.Ref     = columns.Ref;
     this.Spec    = spec;
     this.Columns = columns;
 }