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)); }
/// <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])); }
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(); } }
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)); }
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); }
// 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))); }
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])); } }
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); }
public BpTree(ReferenceAccessor @ref) { this.Ref = @ref; this._root = new RealmArray(@ref); }
public RealmArrayIntNull(ReferenceAccessor @ref) { this._array = new RealmArray(@ref); }
/// <summary> /// サブテーブル /// </summary> public RealmTable(TableSpec spec, RealmArray columns) { this.Ref = columns.Ref; this.Spec = spec; this.Columns = columns; }