Original: Anatomy of SQL Server fifth Orcamdf read bits type data (translated)
Anatomy SQL Server Fifth Orcamdf read bits type data (translated)
http://improve.dk/reading-bits-in-orcamdf/
BITS-type storage is very different from the storage of other SQL Server fixed-length data types. In general, all fixed-length columns are displayed, and the field data for the fixed-length data section of a record is always one next to the other
The smallest unit of data that we can write to a disk is a byte, and the naïve way to store bit type data is to use an entire (byte @) to store each bit, and it's easy to interpret bit-type data in a common format
, but it's a waste of space, like a null bitmap, if a table has only 3 columns, then storing a null bitmap with one byte is wasteful, because no other 5 bits are used
@: In the article is a bit, this should be in bytes
How is the internal bit type stored in the record?
Some bit type column values are stored in one byte and can be up to 8 bits, usually we have the following table definition
CREATE TABLE bittest ( bitbit bits int)
The recorded fixed-length portion of the data needs to occupy 5 bytes, 4 bytes to store the int column, and the other byte to store the data of the three yours faithfully types A, B, C, using only 3 bits in bytes
Let's add some more columns
CREATE TABLEbittest (AbitBbitCbitDintEbitFbitGbitHsmallintIbitJbitKbit)
The e-to-G column should be stored behind the D-column, but they will continue to use the first bit byte until the first bit byte has finished using all of the bit space.
The following figure shows that the H column (smallint) is stored directly behind the column D, and after column D is the new bit byte that stores the K column because the first bit byte is full
The state we need to know when reading the bit types in the row record
Obviously, we can't just read the value of one field at a time, we also need to read the fixed-length data offset pointer
We need to be able to indicate at the time of reading which of the bits in the byte we are currently reading into is the state of which field, and then we read a new bit byte
Let me introduce you to the Recordreadstate class.
Public classrecordreadstate{//We start out has consumed all bits as none has been read Private intCurrentbitindex =8; Private bytebits; Public voidLoadbitbyte (bytebits) { This. bits =bits; Currentbitindex=0; } Public BOOLallbitsconsumed {Get{returnCurrentbitindex = =8; } } Public BOOLgetnextbit () {return(Bits & (1<< currentbitindex++))! =0; }}
The Recordreadstate class currently only needs to process bits, but in the future I may also want to create a bitreadstate class to hold the Read state
The Recordreadstate class holds a byte that is used as a pointer to indicate where the next available bit is in the byte, and if the byte has run out of storage full of bits of data
(Currentbixindex = 8 (0-7 being the available bits), the method allbitsconsumed returns True, indicating that we need to read a new bit byte
The Getnextbit method simply reads the current bit from bit byte and then adds the value of Currentbitindex (bit index) by 1
Demo
usingnunit.framework;usingOrcaMDF.Core.Engine.Records;namespaceorcamdf.core.tests.engine.records{[Testfixture] Public classrecordreadstatetests{[Test] Public voidGeneral () {varState =Newrecordreadstate ();//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 implementation
Once we have the state read, we can implement the Sqlbit type
Public classsqlbit:isqltype{Private ReadOnlyrecordreadstate ReadState; Publicsqlbit (recordreadstate readstate) { This. ReadState =ReadState; } Public BOOLIsvariablelength {Get{return false; } } Public Short?FixedLength {Get { if(readstate.allbitsconsumed)return 1; return 0; } } Public ObjectGetValue (byte[] value) { if(readstate.allbitsconsumed && value.) Length! =1) Throw NewArgumentException ("All bits consumed, invalid value length:"+value. Length); if(value.) Length = =1) Readstate.loadbitbyte (value[0]); returnreadstate.getnextbit (); }}
Sqlbit A read state,read state in the constructor indicates the scope of the current record read operation. It is important to note that the fixed length needs to be based on the current allbitsconsumed value in read state
If all the bits in the byte are occupied, it means that the entire byte needs to be read, if the IF (readstate.allbitsconsumed) returns 0 means that the entire byte is not required, but the GetValue method is still called
The GetValue method verifies a situation where readstate.allbitsconsumed returns true, proving that bit byte is having data stored inside, but value. Length returned is 0, which proves to be a problem.
If we read a value, we ask the read state to load a new bit byte, after which we can call the Getnextbit method to return the current bit of read state
Related tests
usingnunit.framework;usingOrcaMDF.Core.Engine.Records;usingOrcaMDF.Core.Engine.SqlTypes;namespaceorcamdf.core.tests.engine.sqltypes{[Testfixture] Public classsqlbittests {[Test] Public voidGetValue () {varReadState =Newrecordreadstate (); varType =Newsqlbit (ReadState); //No bytes Read-length is oneAssert.AreEqual (1, type. FixedLength); //Load byte and check length is 0Readstate.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 0Assert.AreEqual (0, type. FixedLength); Assert.istrue ((BOOL) type. GetValue (New byte[0])); //All bits consumed-length should is 1Assert.AreEqual (1, type. FixedLength); } }}
End of the fifth chapter
Anatomy SQL Server Fifth Orcamdf read bits type data (translated)