diff --git a/internals/repl/repl.go b/internals/repl/repl.go index 4e2de24..79e6483 100644 --- a/internals/repl/repl.go +++ b/internals/repl/repl.go @@ -37,6 +37,10 @@ func Run() { fmt.Println("Syntax error, could not parse statement") case PrepareUnrecognised: fmt.Printf("Unrecognised keyword at the start of '%s'.\n", inputBuffer.Buffer) + case PrepareTooManyArgs: + fmt.Printf("Too many arguments in the insert statement '%v'\n", inputBuffer.Buffer) + case PrepareValueTooLong: + fmt.Printf("Values for either username or email are too long\n") } switch statement.ExecuteStatement(table) { diff --git a/internals/vm/vm.go b/internals/vm/vm.go index a9b93ab..dec21f6 100644 --- a/internals/vm/vm.go +++ b/internals/vm/vm.go @@ -4,6 +4,8 @@ import ( "encoding/binary" "fmt" "os" + "slices" + "strconv" "strings" . "godb/internals/buffer" @@ -21,6 +23,8 @@ type PrepareResults int const ( PrepareSuccess PrepareResults = iota PrepareUnrecognised + PrepareTooManyArgs + PrepareValueTooLong PrepareSyntaxError ) @@ -151,19 +155,45 @@ func DoMetaCommands(inputBuffer *InputBuffer) MetaCommandResults { return metacommand } +func (statement *Statement) perpareInsert(inputBuffer *InputBuffer) PrepareResults { + inputs := strings.Split(inputBuffer.Buffer, " ")[1:] + if len(inputs) < 3 { + return PrepareSyntaxError + } + if len(inputs) > 3 { + return PrepareTooManyArgs + } + if slices.Contains(inputs, "null") || slices.Contains(inputs, "NULL") || slices.Contains(inputs, "Null") || slices.Contains(inputs, " ") { + return PrepareSyntaxError + } + + tid, err := strconv.ParseUint(inputs[0], 10, 0) + if err != nil { + // fmt.Printf("supplied ID: %v isn't acceptable, please correct and retry\n", inputs[0]) + return PrepareSyntaxError + } + id := uint(tid) + if len(inputs[1]) > usernameSize { + // fmt.Printf("%v is too long for username\n", inputs[1]) + return PrepareValueTooLong + } + if len(inputs[2]) > emailSize { + // fmt.Printf("%v is too long for email\n", inputs[2]) + return PrepareValueTooLong + } + + statement.row.id = id + statement.row.username = inputs[1] + statement.row.email = inputs[2] + + statement.stype = StatementInsert + return PrepareSuccess +} + func (statement *Statement) PrepareStatements(inputBuffer *InputBuffer) PrepareResults { statement.stype = StatementUnrecognized 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 { - return PrepareSyntaxError - } - statement.stype = StatementInsert - return PrepareSuccess + return statement.perpareInsert(inputBuffer) } if inputBuffer.Buffer == "select" { statement.stype = StatementSelect diff --git a/tests/main_test.go b/tests/main_test.go index 029e0b7..94a3b6d 100644 --- a/tests/main_test.go +++ b/tests/main_test.go @@ -106,3 +106,31 @@ func TestTableFull(t *testing.T) { t.Errorf("Our Tables max capacity is 1300 rows, but we're able to insert %v\n", len(results)) } } + +func TestMaxLengthForValues(t *testing.T) { + commands := []string{"insert 0 " + strings.Repeat("n", 32) + " " + strings.Repeat("n", 255), ".exit"} + expected := []string{"godb > Executed.", "godb > bye!"} + + results := runner(commands, t) + for i := range results { + results[i] = strings.ReplaceAll(results[i], "\n", "") + } + + if !slices.Equal(expected, results) { + t.Errorf("Output Mismatch\nExpected: %v\nGot: %v\n", expected, results) + } +} + +func TestOverMaxLengthValues(t *testing.T) { + commands := []string{"insert 0 " + strings.Repeat("n", 42) + " " + strings.Repeat("n", 275), ".exit"} + expected := []string{"godb > Values for either username or email are too long", "godb > bye!"} + + results := runner(commands, t) + for i := range results { + results[i] = strings.ReplaceAll(results[i], "\n", "") + } + + if !slices.Equal(expected, results) { + t.Errorf("Output Mismatch\nExpected: %v\nGot: %v\n", expected, results) + } +}