From 0bc735598f2582dc5a9e91b792998a038be6b3a8 Mon Sep 17 00:00:00 2001 From: chirst Date: Sun, 23 Jun 2024 17:15:08 -0600 Subject: [PATCH] add test --- db.go | 4 ++-- db_test.go | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- kv_test.go | 12 +++++++----- main.go | 2 +- pager.go | 25 ++++++++++++++++--------- 5 files changed, 74 insertions(+), 18 deletions(-) diff --git a/db.go b/db.go index 64066fa..2ed8c3a 100644 --- a/db.go +++ b/db.go @@ -14,8 +14,8 @@ type db struct { vm *vm } -func newDb() (*db, error) { - kv, err := NewKv(false) +func newDb(useMemory bool) (*db, error) { + kv, err := NewKv(useMemory) if err != nil { return nil, err } diff --git a/db_test.go b/db_test.go index 057b152..43da063 100644 --- a/db_test.go +++ b/db_test.go @@ -5,5 +5,52 @@ import ( ) func TestExecute(t *testing.T) { - // TODO + db, err := newDb(true) + if err != nil { + t.Fatal(err) + } + createSql := "CREATE TABLE person (id INTEGER, first_name TEXT, last_name TEXT, age INTEGER)" + createRes := db.execute(createSql) + if createRes.err != nil { + t.Fatal(err.Error()) + } + selectSchemaSql := "SELECT * FROM cdb_schema" + schemaRes := db.execute(selectSchemaSql) + if schemaRes.err != nil { + t.Fatal(schemaRes.err.Error()) + } + schemaSelectExpectations := []string{ + "1", + "table", + "person", + "person", + "2", + "{\"columns\":[{\"name\":\"id\",\"type\":\"INTEGER\"},{\"name\":\"first_name\",\"type\":\"TEXT\"},{\"name\":\"last_name\",\"type\":\"TEXT\"},{\"name\":\"age\",\"type\":\"INTEGER\"}]}", + } + for i, s := range schemaSelectExpectations { + if c := *schemaRes.resultRows[1][i]; c != s { + t.Fatalf("expected %s got %s", s, c) + } + } + insertSql := "INSERT INTO person (first_name, last_name, age) VALUES ('John', 'Smith', 50)" + insertRes := db.execute(insertSql) + if insertRes.err != nil { + t.Fatal(err.Error()) + } + selectPersonSql := "SELECT * FROM person" + selectPersonRes := db.execute(selectPersonSql) + if selectPersonRes.err != nil { + t.Fatal(err.Error()) + } + selectPersonExpectations := []string{ + "1", + "John", + "Smith", + "50", + } + for i, s := range selectPersonExpectations { + if c := *selectPersonRes.resultRows[1][i]; c != s { + t.Fatalf("expected %s got %s", s, c) + } + } } diff --git a/kv_test.go b/kv_test.go index 5161112..4726161 100644 --- a/kv_test.go +++ b/kv_test.go @@ -30,15 +30,17 @@ func TestKv(t *testing.T) { ri := 178 // For a page 4096 a split is more than guaranteed here because // 512*8=4096 not including the header of each page. - for i := 1; i < 512; i += 1 { + keyValueSize := 4 + iters := PAGE_SIZE / 8 + for i := 1; i <= iters; i += 1 { kv.BeginWriteTransaction() k := EncodeKey(uint16(i)) v := []byte{1, 0, 0, 0} - if len(k) != 4 { - t.Fatal("need k to be len 4") + if len(k) != keyValueSize { + t.Fatalf("need k to be len %d", keyValueSize) } - if len(v) != 4 { - t.Fatal("need v to be len 4") + if len(v) != keyValueSize { + t.Fatalf("need v to be len %d", keyValueSize) } kv.Set(1, k, v) if ri == i { diff --git a/main.go b/main.go index 94650d8..58c7426 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,7 @@ package main import "log" func main() { - db, err := newDb() + db, err := newDb(false) if err != nil { log.Fatal(err) } diff --git a/pager.go b/pager.go index 2f765a4..9ac52e6 100644 --- a/pager.go +++ b/pager.go @@ -196,15 +196,22 @@ func (p *pager) allocatePage(pageNumber uint16, content []byte) *page { return np } -// page is structured as follows: -// - 2 bytes for the page type. -// - 4 bytes for the parent pointer. -// - 4 bytes for the left pointer. -// - 4 bytes for the right pointer. -// - 2 bytes for the count of tuples. -// - 4 bytes for the tuple offsets (2 bytes key 2 bytes value) multiplied by the -// amount of tuples. -// - Variable length key and value tuples filling the remaining space. +// page is structured as follows where values accumulate start to end unless +// otherwise specified: +// - 2 bytes for the page type. Which could be internal, leaf or overflow. +// - 4 bytes for the parent pointer (btree). +// - 4 bytes for the left pointer (btree). +// - 4 bytes for the right pointer (btree). +// - 2 bytes for the count of tuples stored on the page. +// - 4 bytes for the tuple offsets (2 bytes key 2 bytes value) multiplied by +// the count of tuples previously mentioned. +// - Variable length key and value tuples filling the remaining space. Which +// accumulates from the end of the page to the start. +// +// TODO could implement overflow pages in case a tuple is larger than some +// threshold (say half the page). There would be another block that would +// contain pointers to overflow pages or be empty. The overflow pages would +// contain a pointer to the next overflow page and content of the overflow. // // Tuple offsets are sorted and listed in order. Tuples are stored in reverse // order starting at the end of the page. This is so the end of each tuple can