0303: 解析select语句
struct 定义
目前只实现了一小部分功能,所以 select 语句只支持一种固定的形式:通过主键来查询某一行数据。比如一个主键是 (c, d) 的表,只能做这种查询:
select a,b from t where c=1 and d='e';用数据结构来表示:
StmtSelect{
table: "t",
cols: []string{"a", "b"},
keys: []NamedCell{
{column: "c", value: Cell{Type: TypeI64, I64: 1}},
{column: "d", value: Cell{Type: TypeStr, Str: []byte("e")}},
},
}暂时定义 struct 如下,以后会逐步增加功能:
type StmtSelect struct {
table string
cols []string
keys []NamedCell
}
type NamedCell struct {
column string
value Cell
}语法解析
语法解析就是从左到右消耗 token,同时构建数据结构的过程。比如要解析 a = 123 这部分语法,输出 NamedCell。依次调用 tryName(),tryPunctuation(),parseValue():
func (p *Parser) parseEqual(out *NamedCell) error {
var ok bool
out.column, ok = p.tryName()
if !ok {
return errors.New("expect column")
}
if !p.tryPunctuation("=") {
return errors.New("expect =")
}
return p.parseValue(&out.value)
}这里新加了 tryPunctuation() 函数。类似 tryKeyword(),但是消耗的一个符号。规则比 keyword 简单。
在解析 WHERE 部分时,循环调用 parseEqual()。即使是复杂的语法,拆分后都很容易。
解析 select 语句
首先开头的 select 关键字可以区分不同的SQL语句,不过现在只实现一个语句。然后是一串逗号分隔的列名,直到碰到 from 终止。
func (p *Parser) parseSelect(out *StmtSelect) error {
if !p.tryKeyword("SELECT") {
return errors.New("expect keyword")
}
for !p.tryKeyword("FROM") {
if len(out.cols) > 0 && !p.tryPunctuation(",") {
return errors.New("expect comma")
}
if name, ok := p.tryName(); ok {
out.cols = append(out.cols, name)
} else {
return errors.New("expect column")
}
}
if len(out.cols) == 0 {
return errors.New("expect column list")
}
var ok bool
if out.table, ok = p.tryName(); !ok {
return errors.New("expect table name")
}
return p.parseWhere(&out.keys)
}解析 WHERE
这部分暂时只支持用 AND 分隔的 a = 123。跟 SELECT a,b 类似,只不过逗号换成 AND,tryName() 换成 parseEqual()。读者自己完成吧:
func (p *Parser) parseWhere(out *[]NamedCell) error