国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

解剖SQLSERVER 第五篇 OrcaMDF里讀取Bits類型數據(譯)

2024-07-21 02:48:58
字體:
來源:轉載
供稿:網友
解剖SQLSERVER 第五篇 OrcaMDF里讀取Bits類型數據(譯)解剖SQLSERVER 第五篇 OrcaMDF里讀取Bits類型數據(譯)

http://imPRove.dk/reading-bits-in-orcamdf/

Bits類型的存儲跟SQLSERVER其他定長數據類型的存儲很不一樣。通常,所有定長列都會顯示出來,一個條記錄里定長數據部分的字段數據總是一個挨著一個

我們可以寫入磁盤的最小數據單位是一個字節,存儲位類型數據的天真的方法就是使用一整個(字節@)來存儲每一個位,使用常用的格式去解釋位類型數據是很簡單的

,不過這會浪費一些空間 ,就像null位圖,如果一個表只有3列,那么用一個字節來存儲null位圖會比較浪費,因為其他的5個位都沒有用到

@:文章里是用位 ,這里應該是用字節吧

在記錄的內部位類型是如何存儲的?

一些位類型列的值是存儲在一個字節中的,最大可以到8個位,通常,我們會有如下表定義

CREATE TABLE BitTest(    A bit    B bit    C bit    D int)

記錄的定長部分數據需要占用5個字節,4個字節存儲int 列 ,而另一個字節存儲A 、B、C這三列位類型的數據,只用了字節里面的3個位

我們再添加一些列

CREATE TABLE BitTest(    A bit    B bit    C bit    D int    E bit    F bit    G bit    H smallint    I bit    J bit    K bit)

E到G列按道理來說應該存儲在D列的后面,但是他們會繼續使用第一個 bit byte,直到第一個 bit byte使用完所有的位空間為止

下面的圖顯示了H列(smallint)直接存儲在D列的后面,而在D列后面是存儲K列的新bit byte,因為第一個bit byte已經滿了

當讀取行記錄里的位類型時我們需要知道的狀態

很明顯,我們一次不能只讀取一個字段的值,我們讀取固定長度數據類型的時候還需要讀取定長數據偏移指針

我們需要一些能在讀取的時候指示我們當前讀取到字節中哪一個位屬于哪一個字段的狀態,然后我們讀取一個新的bit byte

我來介紹一下RecordReadState類

public class RecordReadState{    // We start out having consumed all bits as none have been read    private int currentBitIndex = 8;    private byte bits;    public void LoadBitByte(byte bits)    {        this.bits = bits;        currentBitIndex = 0;    }    public bool AllBitsConsumed    {        get { return currentBitIndex == 8; }    }    public bool GetNextBit()    {        return (bits & (1 << currentBitIndex++)) != 0;    }}

RecordReadState 類當前只需要處理bits,但是將來我可能還要創建一個BitReadState 類用來保存讀取狀態

RecordReadState 類保存了一個字節用來當作指針指出下一個可用的位在字節的哪個地方,如果字節已經用完了存儲滿了所有的位數據

(currentBixIndex = 8 (0-7 being the available bits)),方法AllBitsConsumed 就會返回true,指示我們需要讀取一個新的bit byte

GetNextBit方法只是簡單的從bit byte中讀取當前的bit ,然后將currentBitIndex(bit index)的值加1

demo

using NUnit.Framework;using OrcaMDF.Core.Engine.Records;namespace OrcaMDF.Core.Tests.Engine.Records{    [TestFixture]public class RecordReadStateTests{        [Test]public void General(){var state = new RecordReadState();// No bits availableAssert.IsTrue(state.AllBitsConsumed);state.LoadBitByte(0xD2); // 11010010// Bits availableAssert.IsFalse(state.AllBitsConsumed);// Reading bit valuesAssert.IsFalse(state.GetNextBit());Assert.IsTrue(state.GetNextBit());Assert.IsFalse(state.GetNextBit());Assert.IsFalse(state.GetNextBit());Assert.IsTrue(state.GetNextBit());Assert.IsFalse(state.GetNextBit());Assert.IsTrue(state.GetNextBit());// One bit leftAssert.IsFalse(state.AllBitsConsumed);Assert.IsTrue(state.GetNextBit());// Bits exhausted, ready for next byteAssert.IsTrue(state.AllBitsConsumed);}}}

SqlBit實現

一旦我們實現了狀態的讀取,我們就可以實現SqlBit 類型

public class SqlBit : ISqlType{    private readonly RecordReadState readState;    public SqlBit(RecordReadState readState)    {        this.readState = readState;    }    public bool IsVariableLength    {        get { return false; }    }    public short? FixedLength    {        get        {            if (readState.AllBitsConsumed)                return 1;            return 0;        }    }    public object GetValue(byte[] value)    {        if(readState.AllBitsConsumed && value.Length != 1)            throw new ArgumentException("All bits consumed, invalid value length: " + value.Length);        if (value.Length == 1)            readState.LoadBitByte(value[0]);        return readState.GetNextBit();    }}

SqlBit 在構造函數里傳入一個read state,read state指示當前記錄讀取操作的范圍。需要注意的是固定長度需要依據read state里的當前AllBitsConsumed值

如果字節里面所有位都被占用,那么意味著需要讀取整個字節,如果if (readState.AllBitsConsumed)返回0表示不需要讀取整個字節,但是GetValue方法依然會被調用

GetValue方法會驗證一種情況:readState.AllBitsConsumed 返回真,證明 bit byte是有數據存儲在里面,但是value.Length返回的長度是0,那證明有問題了

如果我們讀到一個值,我們會請求read state 去裝載一個新的bit byte ,之后,我們可以調用GetNextBit 方法返回read state的當前bit

相關測試

using NUnit.Framework;using OrcaMDF.Core.Engine.Records;using OrcaMDF.Core.Engine.SqlTypes;namespace OrcaMDF.Core.Tests.Engine.SqlTypes{    [TestFixture]    public class SqlBitTests    {        [Test]        public void GetValue()        {            var readState = new RecordReadState();            var type = new SqlBit(readState);            // No bytes read - length is one            Assert.AreEqual(1, type.FixedLength);            // Load byte and check length is 0            readState.LoadBitByte(0xD2);            Assert.AreEqual(0, type.FixedLength);            Assert.IsFalse((bool)type.GetValue(new byte[0]));            Assert.IsTrue((bool)type.GetValue(new byte[0]));            Assert.IsFalse((bool)type.GetValue(new byte[0]));            Assert.IsFalse((bool)type.GetValue(new byte[0]));            Assert.IsTrue((bool)type.GetValue(new byte[0]));            Assert.IsFalse((bool)type.GetValue(new byte[0]));            Assert.IsTrue((bool)type.GetValue(new byte[0]));            // One bit left - length should still be 0            Assert.AreEqual(0, type.FixedLength);            Assert.IsTrue((bool)type.GetValue(new byte[0]));            // All bits consumed - length should be 1            Assert.AreEqual(1, type.FixedLength);        }    }}

第五篇完


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阳东县| 安福县| 临澧县| 垣曲县| 金堂县| 呼和浩特市| 大厂| 托里县| 夏津县| 永泰县| 吉木乃县| 堆龙德庆县| 浦城县| 乌兰察布市| 报价| 广德县| 庆阳市| 清丰县| 丰原市| 抚顺市| 乐平市| 湖口县| 杭州市| 新干县| 苏尼特右旗| 临夏县| 陆丰市| 衡东县| 随州市| 乐昌市| 东海县| 英超| 绍兴市| 蒲江县| 卓资县| 通城县| 龙南县| 连江县| 平谷区| 屏边| 聂拉木县|