Repository navigation
1.0
StoopidDB version 1.0's structure is as follows:
[0]
-HEADER
-BODY (DATA) - TABLES
-ENTRY TABLE
-ENTRY TABLE OFFSET
[EOF]The DB starts with a 13 byte header that looks like this:
[0-8] = .ascii "StoopidDB"
[9] = \x0
[0-9] = .string "StoopidDB\x0"
[10] = Major version i.e \0x1 = 1
[11] = Minor version i. e \0x0 = 0
[12] = \x0 For for spacingAfter the header, the body of the table starts.
The body is made of both the tables and the rows and could look a little like this:
[0x0] 48 61 74 73
[0x4] 00 C5 02 00
[0x8] 00 00 00 00
[0xC] 00 02 00 00
[0x10] 00 49 44 00
[0x14] 0D 00 00 00
[0x18] 00 A0 08 00
[0x1C] 00 00 53 69
[0x20] 7A 65 00 0F
[0x24] 00 00 00 00
[0x28] 80 08 00 00
[0x2C] 00As hex it doesn't make much sense - so we translate it.
Let's first take a look at the structure of the table:
[0-(max)255] = Nullterminated name with a max size of 256
[256-263] = EOT OFFSET = End of Table offset - 8 bytes long
[264-268] = Amount of columns - 4 bytes long
[268-EOT] = Columns and Rows - can use all space between 268 and EOTTo dig a little further into this structure, we're going to take a look at an example (The HexDump above)
The first 5 bytes is the name of the table and can be up to 255 bytes long. If the name is smaller that 255, the string is null terminated like this:
[0x0] 48 61 74 73 = "Hats"
[0x4] 00 = NULL-terminatorThis example was taken from a large database so the next part may be a little strange, but the next part is the EOT-Offset.
The EOT-Offset is the offset where the table ends, and is used to quickly find out where the next table is located by being able to skip the table quickly. The offset pointer is always 8 bytes long. From the example table:
[0x5] { C5 02 00 00
[0x9] 00 00 00 00 } = unsigned int64 = 0x00000000000002C5 = 709This would mean that the table ends in offset 0x02C5 - If you then take the entry pointer found in the entry table (explained below/here) you would be able to use the EOT-Offset to calculate the size of the table itself.
The next 4 bytes is used to store the amount of columns in the table. From the example:
[0xD] { 02 00 00 00 } = unsigned int32 = 0x2 = 2This would mean that the table has 2 columns.
The next thing in the table is the columns. The columns are structured as follows:
[0-(max)255] First colum name (256 B max)
[256-260] Column size 4 bytes
[261] DataTypeByte
[262] SettingsByte
[263-267] Max data size (how much the data can take up) // 4 bytesThe settingsbyte and the datatypebyte is evaluated bitwise like this:
The settingsbyte exists to tell the database about the special properties of the column.
0b00000000 = "NONE"
0b10000000 = "NOT NULL"
0b01000000 = "AUTO INCREMENT"
0b0010000 = "PRIMARY KEY"
The datatypebyte exists to tell the database what kind of data is being stored in the column.
0b00000000 = INT
0b10000000 = VARCHAR
0b01000000 = TIME_DATE (UnixTime)
0b00100000 = UNSIGNED VARCHAR (VARCHAR where all bytes are unsigned)To see the structure in action we're going back to the example.
As we figured out before - we should have 2 columns so we expect the data to reflect that.
That means that what we expect of the next section of hex should be a null-terminated name of a column.
[0x11] 49 44 = "ID"
[0x13] 00 = NULL-terminatorAnd it was!
After that we'll have to decode the length of the column: (NOTE: it's NOT the offset, but the LENGTH)
[0x14] { 0D 00 00 00 } = unsigned int32 = 0xD = 13That also means that we can expect to find the next column 13 bytes further down:
[0x1E] 53 69 7A 65 = "Size"
[0x22] 00 = NULL-terminatorAnd again - Success!
That proves that the size was read correctly.
Before tackling the second column, let's finish the first one first.
The next thing we need to handle is the two single bytes.
[0x18] 00 = DataTypeByte = 0 = INT
[0x19] A0 = SettingsByteThe DataTypeByte is just 0 so we know that the data type is INT, but the second needs to be shown in bits first:
[0x19] A0 = 0b10100000 = "NOT NULL" && "PRIMARY KEY"We see that the first and third bits are set - That means that it's set as NOT NULL and PRIMARY KEY.
We also see that the second bit is not set so the column will not AUTO INCREMENT. In this case the column will actually be automatically incremented as the PRIMARY KEY setting automatically assumes that it should be automatically incremented (This is a bug).
EVERYTHING BELOW THIS TEXT IS OLD AND MAY OR MAY NOT BE ACCURATE - THE INFORMATION BELOW WILL BE REVISED AT A LATER DATE
Last 8 bytes = [EOF-8] = EntryTableStartPointer
[EntryTableStart]
every entry is starting with "E" 0xFF "N" 0xFF "T" 0xFF and is MAX 256+4+8+6 bytes long - continues with a 4 byte int representing the length of the entry, followed nullterminated string (the table name) that is never more than 256 characters long followed by a 8 byte long offset into the file acting as a pointer
The EntryTable ends with the signature:
\[0\] = \x0
\[1\] = \xFF
\[2\] = \xFF
\[3\] = \x0
\[4\] = \x0
\[5\] = \xFF
\[6\] = \xFF
\[7\] = \x0
\[0-255\]Nullterminated name with a max size of 256 (ALWAYS STOP AT 255, EVEN IF A NULL IS NOT FOUND!)
\[(max)256-263\] EOT OFFSET = End of Table offset - 8 bytes long
\[264-268\]Amount of columns - 4 bytes long
\[0-(max)255\] First colum name (256 B max)
\[256-260\] Column size 4 bytes
\[261\] Type of data in column (0 = int, 1 = varchar, 2 = TIME_DATE (UnixTime), 3 = Unsigned VarChar)
\[262\] SettingsByte (00000000) 1 = (0b10000000) = "NOT NULL", 2 = AUTOINCREMENT, 4 = PRIMARY_KEY
\[263-267\] Max data size (how much the data can take up) // 4 bytes
RowSignature = uchar\[6\]{
\[0\]R,
\[1\]\0,
\[2\]\O,
\[3\]\0,
\[4\]\W,
\[5\]\0
}
length of row = 8 bytes
Repeating - end is located at offset+len{
columnId = 4 bytes
Data = MaxSizeOfColumnByIdInBytes
}
//TODO - Add space for saving variables that needs to be used later (like the autoincrement tmp variable)