Files

185 lines
3.9 KiB
Go
Raw Permalink Normal View History

2026-07-20 00:32:34 +05:30
package vm
import (
"encoding/binary"
2026-07-20 00:32:34 +05:30
"fmt"
"os"
"strings"
. "godb/internals/buffer"
)
type MetaCommandResults int
const (
MetaCommandSuccess MetaCommandResults = iota
MetaCommandUnrecognised
)
type PrepareResults int
const (
PrepareSuccess PrepareResults = iota
PrepareUnrecognised
PrepareSyntaxError
)
type statementType int
const (
StatementSelect statementType = iota
StatementInsert
StatementUnrecognized
2026-07-20 00:32:34 +05:30
)
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
ExecuteFail
)
2026-07-20 00:32:34 +05:30
type row struct {
id uint
username string
email string
}
type Statement struct {
stype statementType
row row
}
2026-07-21 23:22:15 +05:30
type Table struct {
numOfRows uint
pages [maxPages]any
}
2026-07-20 00:32:34 +05:30
func NewStatement() *Statement {
statement := &Statement{}
return statement
2026-07-20 00:32:34 +05:30
}
2026-07-21 23:22:15 +05:30
func NewTable() *Table {
newTable := Table{numOfRows: 0}
for i := range maxPages {
newTable.pages[i] = nil
}
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
}
2026-07-20 00:32:34 +05:30
func DoMetaCommands(inputBuffer *InputBuffer) MetaCommandResults {
metacommand := MetaCommandUnrecognised
if inputBuffer.Buffer == ".exit" {
fmt.Println("bye!")
os.Exit(0)
} else {
metacommand = MetaCommandUnrecognised
}
return metacommand
}
func (statement *Statement) PrepareStatements(inputBuffer *InputBuffer) PrepareResults {
statement.stype = StatementUnrecognized
2026-07-20 00:32:34 +05:30
if strings.HasPrefix(inputBuffer.Buffer, "insert") {
argsAssigned, err := fmt.Sscanf(inputBuffer.Buffer, "insert %d %s %s", &statement.row.id, &statement.row.username, &statement.row.email)
if err != nil {
fmt.Println("error parsing insert statement")
fmt.Println(err.Error())
}
if err != nil || argsAssigned > 3 {
2026-07-20 00:32:34 +05:30
return PrepareSyntaxError
}
statement.stype = StatementInsert
return PrepareSuccess
}
if strings.HasPrefix(inputBuffer.Buffer, "select") {
statement.stype = StatementSelect
return PrepareSuccess
}
return PrepareUnrecognised
}
func (statement *Statement) ExecuteStatement(table *Table) ExecuteResult {
var result ExecuteResult = ExecuteFail
2026-07-20 00:32:34 +05:30
switch statement.stype {
case StatementInsert:
result = statement.execInsert(table)
2026-07-20 00:32:34 +05:30
case StatementSelect:
result = statement.execSelect(table)
2026-07-20 00:32:34 +05:30
}
return result
2026-07-20 00:32:34 +05:30
}