英文:
gob decoder returns only first element in the array
问题
所以我正在尝试创建一个模拟数据库,在当前的实现中,我试图创建一个insert
和select
,其中insert
插入行,select
返回它们。我决定使用bytes.Buffer
来帮助维护一个内存块,我可以在其中插入一系列行,并在调用select
时反序列化该内存块,但似乎select
只返回第一行,而不是传递给数组的所有行。
上面的代码负责收集用户输入等。
以下是负责解析用户输入并将条目附加到语句中的代码,根据关键字,它可以是insert
或select
(已删除定义枚举的代码,只保留核心逻辑)。
代码使用全局的buffer
,在PrepareStatement()
中附加的slice
将在执行insert
后进行编码。select
应该返回所有行的slice
,但出于某种原因只返回第一个元素。
例如(在终端中):
如果我进行两次插入:
db > insert 1 john c@mail.com
db > insert 2 collins k@mail.com
然后我进行一个选择:
select
=> 它只返回[{1 john c@mail.com}]
。
这里有什么我漏掉的吗?感谢您的支持。
英文:
So I was trying to create a mock DB, and in the current implementation, I am trying to make an insert
and select
which insert rows and select
returns them. I decided to use a bytes.Buffer
to help maintain a memory block I could insert a slice of rows in, and deserialize that memory block when I call select
but it seems select
just returns the first row instead of all the rows passed to the array.
main.go
func main() {
inputBuffer := compiler.NewInputBuffer()
scanner := bufio.NewScanner(os.Stdin)
for {
PrintPrompt()
scanner.Scan()
command := scanner.Text()
inputBuffer.Buffer = command
if strings.HasPrefix(inputBuffer.Buffer, ".") {
switch compiler.DoMetaCommand(inputBuffer) {
case compiler.MetaCommandSuccess:
continue
case compiler.MetaCommandUnrecognizedCommand:
fmt.Printf("Unrecognized command %q \n", inputBuffer.Buffer)
continue
}
}
var statement compiler.Statement
switch compiler.PrepareStatement(inputBuffer, &statement) {
case compiler.PrepareSuccess:
case compiler.PrepareUnrecognizedStatement:
fmt.Printf("Unrecognized command at start of %q \n", inputBuffer.Buffer)
continue
case compiler.PrepareSyntaxError:
fmt.Println("Syntax error. Could not parse statement.")
continue
}
compiler.ExecuteStatement(statement)
fmt.Println("Executed")
}
}
func PrintPrompt() {
fmt.Printf("db > ")
}
Above is the code responsible for collecting user input etc.
package compiler
import (
"bytes"
"log"
"os"
"strconv"
"strings"
)
type Row struct {
ID int32
Username string
Email string
}
type Statement struct {
RowToInsert Row
Type StatementType
}
var (
RowsTable = make([]Row, 0)
RowsTableBuffer bytes.Buffer
)
func DoMetaCommand(buffer InputBuffer) MetaCommandResult {
if buffer.Buffer == ".exit" {
os.Exit(0)
} else {
return MetaCommandUnrecognizedCommand
}
return MetaCommandSuccess
}
func PrepareStatement(buffer InputBuffer, statement *Statement) PrepareResult {
if len(buffer.Buffer) > 6 {
bufferArguments := strings.Fields(buffer.Buffer)
if bufferArguments[0] == "insert" {
statement.Type = StatementInsert
if len(bufferArguments) < 4 {
return PrepareSyntaxError
} else {
i, err := strconv.Atoi(bufferArguments[1])
if err != nil {
log.Printf("%q is not a valid id\n", bufferArguments[1])
return PrepareSyntaxError
} else {
statement.RowToInsert.ID = int32(i)
}
statement.RowToInsert.Username = bufferArguments[2]
statement.RowToInsert.Email = bufferArguments[3]
}
RowsTable = append(RowsTable, statement.RowToInsert)
return PrepareSuccess
}
}
if buffer.Buffer == "select" {
statement.Type = StatementSelect
return PrepareSuccess
}
return PrepareUnrecognizedStatement
}
func ExecuteStatement(statement Statement) {
switch statement.Type {
case (StatementInsert):
SerializeRow(RowsTable)
case (StatementSelect):
DeserializeRow()
}
}
The code above is for parsing and appending the entries into statements and depending on the keywords, it's either an insert
or select
[Took the code for defining enums out and left core logic]
func SerializeRow(r []Row) {
encoder := gob.NewEncoder(&RowsTableBuffer)
err := encoder.Encode(r)
if err != nil {
log.Println("encode error:", err)
}
}
func DeserializeRow() {
var rowsBuffer = RowsTableBuffer
rowsTable := make([]Row, 0)
decoder := gob.NewDecoder(&rowsBuffer)
err := decoder.Decode(&rowsTable)
if err != nil {
log.Println("decode error:", err)
}
fmt.Println(rowsTable)
}
So the code above uses a global buffer
in which the slice
being appended to in PrepareStatement()
will be encoded after an insert
is done. A select
ought to return the slice of all rows but just returns the first element for some reason.
Example (in terminal):
If I make 2 inserts:
db > insert 1 john c@mail.com
db > insert 2 collins k@mail.com
Then I make a select:
select
=> it returns [{1 john c@mail.com}]
only.
Is there anything I am missing here? Thanks for your support.
答案1
得分: 0
所以答案很简单。我们在SerializeRow
函数中创建了一个新的encoder
,而不是只创建一次。我们将其从函数中提取出来,创建为全局变量。
var (
encoder = gob.NewEncoder(&RowsTableBuffer)
decoder = gob.NewDecoder(&RowsTableBuffer)
)
func SerializeRow(r Row) {
err := encoder.Encode(r)
if err != nil {
log.Println("encode error:", err)
}
}
func DeserializeRow() {
var rows Row
err := decoder.Decode(&rows)
for err == nil {
if err != nil {
log.Fatal("decode error:", err)
}
fmt.Printf("%d %s %s\n", rows.ID, rows.Username, rows.Email)
err = decoder.Decode(&rows)
}
}
英文:
So the answer was pretty simple. We were creating a new encoder
in the SerializeRow
function instead of creating it once. We pulled it out of the function and created a global.
var (
encoder = gob.NewEncoder(&RowsTableBuffer)
decoder = gob.NewDecoder(&RowsTableBuffer)
)
func SerializeRow(r Row) {
err := encoder.Encode(r)
if err != nil {
log.Println("encode error:", err)
}
}
func DeserializeRow() {
var rows Row
err := decoder.Decode(&rows)
for err == nil {
if err != nil {
log.Fatal("decode error:", err)
}
fmt.Printf("%d %s %s\n", rows.ID, rows.Username, rows.Email)
err = decoder.Decode(&rows)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论