public override IEnumerable <KeyValuePair <K, int> > CompareNonIndexedKeyWithKey <K, T>( DbColumn key, DbColumn column, TokenType comparer, T value) { if (column.Indexed || column.Table.Multikey) { throw new ArgumentException($"Column {column} must be un-indexed, and belong to a One-Key table"); } //get the key column, index var keyColumn = column.Table.Key; int keyColumnIndex = column.Index; K keyValue = default(K); var keyCount = 0; //read indexer offsets in their order using (var keyReader = new io.BinaryReader( io.File.OpenRead($"{key.Table.Database.BinaryPath}\\{key.Hash}.offset"))) { //amount of keys keyCount = keyReader.ReadInt32(); var count = Table.Count; var initialCount = column.Index; var buffer = new byte[sizeof(UInt64)]; var bytes = Table.RowMaskLength; var mainMask = Table.RowMask; int columnIndex = 0; int columnSize = 0; int bytesToSkip = 0; ulong bitMask = 0; ulong recordMask = 0; void SKIP(int cnt) { while (cnt-- > 0) { if ((recordMask & bitMask) == 0) { if (columnIndex == keyColumnIndex) { //read Key value into: keyValue keyValue = GetColumnValue <K>(); } else { //SKIP //not null value, add according to column type if (columnSize == 0) { throw new ArgumentException("unsupported type size"); } else if (columnSize > 0) { bytesToSkip += columnSize; } else { //string, read length, and add chars reader.BaseStream.Position += bytesToSkip; //read new bytes to skip bytesToSkip = reader.ReadByte(); } } } bitMask >>= 1; columnSize = ColumnTypeSizes[++columnIndex]; } //position reader if (bytesToSkip > 0) { reader.BaseStream.Position += bytesToSkip; } } C GetColumnValue <C>() { //for string, read length byte var size = (columnSize < 0) ? reader.ReadByte() : columnSize; //create buffer var columnBuffer = new byte[size]; //read it reader.Read(columnBuffer, 0, size); //convert it to generic value return(columnBuffer.BitConvertTo <C>()); } for (var ndx = 0; ndx < keyCount; ndx++) { var offset = keyReader.ReadInt32(); //point to record offset reader.BaseStream.Position = offset; //copy main mask bitMask = mainMask; //read record mask reader.Read(buffer, 0, bytes); recordMask = BitConverter.ToUInt64(buffer, 0); //developer only var binary = Convert.ToString((long)recordMask, 2); // columnSize = ColumnTypeSizes[columnIndex = 0]; bytesToSkip = 0; //skip initial columns if any if (initialCount > 0) { SKIP(initialCount); } //read column value to compare var columnValue = GetColumnValue <T>(); if (comparer.Compare <T>(columnValue, value)) { if (keyColumnIndex > columnIndex) { //key not read yet SKIP(keyColumnIndex - columnIndex - 1); //read Key value into: keyValue keyValue = GetColumnValue <K>(); } yield return(new KeyValuePair <K, int>(keyValue, offset)); } } } }
/// <summary> /// Expensive non-indexed column comparison by a constant value /// </summary> /// <typeparam name="T">type of column</typeparam> /// <param name="key">table key</param> /// <param name="column">column to compare</param> /// <param name="comparer">comparison operator</param> /// <param name="value">constant value</param> /// <returns></returns> public override IEnumerable <int> CompareNonIndexedKey <T>( DbColumn key, DbColumn column, TokenType comparer, T value) { //THIS CANNOT BE TOGETHER WITH CompareNonIndexedKeyWithKey BECAUSE // RETURNING KEY MAKE AN EXTRA LOAD var keyCount = 0; //read indexer offsets in their order using (var keyReader = new io.BinaryReader( io.File.OpenRead($"{key.Table.Database.BinaryPath}\\{key.Hash}.offset"))) { keyCount = keyReader.ReadInt32(); var count = Table.Count; var initialCount = column.Index; var buffer = new byte[sizeof(UInt64)]; var bytes = Table.RowMaskLength; var mainMask = Table.RowMask; int columnIndex = 0; int columnSize = 0; int bytesToSkip = 0; ulong bitMask = 0; ulong recordMask = 0; //build column type translator var columnTypeSizes = Table.ColumnTypes.Select(t => t.GetSize()).ToArray(); void SKIP(int cnt) { while (cnt-- > 0) { if ((recordMask & bitMask) == 0) { //not null value, add according to column type var size = columnTypeSizes[columnIndex]; if (size == 0) { throw new ArgumentException("unsupported type size"); } else if (size > 0) { bytesToSkip += size; } else { //string, read length, and add chars reader.BaseStream.Position += bytesToSkip; //read new bytes to skip bytesToSkip = reader.ReadByte(); } } bitMask >>= 1; columnSize = ColumnTypeSizes[++columnIndex]; } //position reader if (bytesToSkip > 0) { reader.BaseStream.Position += bytesToSkip; } } T GetColumnValue <T>() { //for string, read length byte var size = (columnSize < 0) ? reader.ReadByte() : columnSize; //create buffer var columnBuffer = new byte[size]; //read it reader.Read(columnBuffer, 0, size); //convert it to generic value return(columnBuffer.BitConvertTo <T>()); } for (var ndx = 0; ndx < keyCount; ndx++) { var offset = keyReader.ReadInt32(); //point to record offset reader.BaseStream.Position = offset; //copy main mask bitMask = mainMask; //read record mask reader.Read(buffer, 0, bytes); recordMask = BitConverter.ToUInt64(buffer, 0); //developer only var binary = Convert.ToString((long)recordMask, 2); columnSize = ColumnTypeSizes[columnIndex = 0]; bytesToSkip = 0; //skip initial columns if any if (initialCount > 0) { SKIP(initialCount); } //read column value to compare var columnValue = GetColumnValue <T>(); //compare if (comparer.Compare <T>(columnValue, value)) { yield return(offset); } } } }