diff --git a/internals/repl/repl.go b/internals/repl/repl.go index 49ab463..173a2a3 100644 --- a/internals/repl/repl.go +++ b/internals/repl/repl.go @@ -38,8 +38,12 @@ func Run() { continue } - statement.ExecuteStatement(table) - fmt.Println("Executed") + switch statement.ExecuteStatement(table) { + case ExecuteSuccess: + fmt.Println("Executed.") + case ExecuteTableFull: + fmt.Println("Error: Table is full") + } } } diff --git a/internals/vm/vm.go b/internals/vm/vm.go index 354baf4..794d4ae 100644 --- a/internals/vm/vm.go +++ b/internals/vm/vm.go @@ -1,6 +1,7 @@ package vm import ( + "encoding/binary" "fmt" "os" "strings" @@ -30,6 +31,29 @@ const ( StatementInsert ) +const ( + idSize = 8 + usernameSize = 32 + emailSize = 255 + + idOffset = 0 + usernameOffset = idOffset + idSize + emailOffset = usernameOffset + usernameSize + + pageSize = 4096 + maxPages = 100 + rowSize = idSize + usernameSize + emailSize + rowsPerPage = pageSize / rowSize + maxRows = rowsPerPage * maxPages +) + +type ExecuteResult int + +const ( + ExecuteSuccess ExecuteResult = iota + ExecuteTableFull +) + type row struct { id uint username string @@ -41,11 +65,6 @@ type Statement struct { row row } -const ( - _pageSize = 4096 - maxPages = 100 -) - type Table struct { numOfRows uint pages [maxPages]any @@ -63,6 +82,61 @@ func NewTable() *Table { return &newTable } +func rowToUse(table *Table, rowNo uint) []byte { + pageNo := rowNo / rowsPerPage + var page []byte + if table.pages[pageNo] == nil { + page = make([]byte, pageSize) + table.pages[pageNo] = page + } else { + i := table.pages[pageNo] + if t, ok := i.([]byte); !ok { + page = []byte(t) + } else { + page = t + } + } + rowOffset := rowNo % rowsPerPage + byteOffset := rowOffset * rowSize + return page[byteOffset : byteOffset+rowSize] +} + +func (row *row) seralizeRow(page []byte) { + binary.NativeEndian.PutUint64(page[idOffset:], uint64(row.id)) + + usernameBuff := page[usernameOffset : usernameOffset+usernameSize] + clear(usernameBuff) + copy(usernameBuff, row.username) + + emailBuff := page[emailOffset : emailOffset+emailSize] + clear(emailBuff) + copy(emailBuff, row.email) +} + +func (row *row) deSeralizeRow(page []byte) { + row.id = uint(binary.NativeEndian.Uint64(page[idOffset:idSize])) + row.username = string(page[usernameOffset : usernameOffset+usernameSize]) + row.email = string(page[emailOffset : emailOffset+emailSize]) +} + +func (statement *Statement) execInsert(table *Table) ExecuteResult { + if table.numOfRows >= maxRows { + return ExecuteTableFull + } + statement.row.seralizeRow(rowToUse(table, table.numOfRows)) + table.numOfRows += 1 + return ExecuteSuccess +} + +func (statement *Statement) execSelect(table *Table) ExecuteResult { + var row row + for i := range table.numOfRows { + row.deSeralizeRow(rowToUse(table, i)) + fmt.Printf("%v\n", row) + } + return ExecuteSuccess +} + func DoMetaCommands(inputBuffer *InputBuffer) MetaCommandResults { metacommand := MetaCommandUnrecognised if inputBuffer.Buffer == ".exit" { @@ -94,11 +168,13 @@ func (statement *Statement) PrepareStatements(inputBuffer *InputBuffer) PrepareR return PrepareUnrecognised } -func (statement *Statement) ExecuteStatement(table *Table) { +func (statement *Statement) ExecuteStatement(table *Table) ExecuteResult { + var result ExecuteResult switch statement.stype { case StatementInsert: - fmt.Println("This is where the logic of insert statement should go") + result = statement.execInsert(table) case StatementSelect: - fmt.Println("This is where the logic of select statement should go") + result = statement.execSelect(table) } + return result }