gob解码器只返回数组中的第一个元素。

huangapple go评论85阅读模式
英文:

gob decoder returns only first element in the array

问题

所以我正在尝试创建一个模拟数据库,在当前的实现中,我试图创建一个insertselect,其中insert插入行,select返回它们。我决定使用bytes.Buffer来帮助维护一个内存块,我可以在其中插入一系列行,并在调用select时反序列化该内存块,但似乎select只返回第一行,而不是传递给数组的所有行。

上面的代码负责收集用户输入等。

以下是负责解析用户输入并将条目附加到语句中的代码,根据关键字,它可以是insertselect(已删除定义枚举的代码,只保留核心逻辑)。

代码使用全局的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)

	}

}

huangapple
  • 本文由 发表于 2022年4月12日 06:36:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/71835056.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定