0501: 中缀表达式
用树型结构来表示任意表达式
要让 SQL 支持上一步增加的范围查询功能,就要解析更复杂的语法。之前只能解析这种固定形式的 WHERE:
select a, b from t where a = 123 and b = 456;现在要支持这种形式:
select a, b from t where a > 123;
select a, b from t where (a, b) > (123, 0);需要用数据结构来表示 WHERE 中的各种表达式(expression):
type ExprBinOp struct {
op ExprOp
left interface{}
right interface{}
}比如:
// a = 123 and b = 456
ExprBinOp{op: OP_AND,
left: &ExprBinOp{op: OP_EQ,
left: "a",
right: &Cell{Type: TypeI64, I64: 123}},
right: &ExprBinOp{op: OP_EQ,
left: "b",
right: &Cell{Type: TypeI64, I64: 456}}}
// a > 123
ExprBinOp{op: OP_GT,
left: "a",
right: &Cell{Type: TypeI64, I64: 123}}用 interface{} 可以引用任意数据类型,相当于C/C++里的 void *,但带有类型信息,可以判断并转换回原始类型。这里用到3种类型:
- 字符串表示一个列名。
&Cell{}表示常数。&ExprBinOp{}表示嵌套的表达式。
解析中缀表达式
这一步先不考虑运算优先级,解析只包含 +- 号的表达式:
// a
"a"
// a + b
&ExprBinOp{op: OP_ADD, left: "a", right: "b"}
// a + b - 3
&ExprBinOp{op: OP_SUB,
left: &ExprBinOp{op: OP_ADD, left: "a", right: "b"},
right: &Cell{Type: TypeI64, I64: 123}}操作的对象包括列名和常数,返回 interface{}:
func (p *Parser) parseAtom() (interface{}, error) {
if name, ok := p.tryName(); ok {
return name, nil
}
cell := &Cell{}
if err := p.parseValue(cell); err != nil {
return nil, err
}
return cell, nil
}实现 parseAdd() 函数,循环调用 parseAtom()、tryPunctuation():
func (p *Parser) parseAdd() (interface{}, error)您正在阅读免费版教程,从第4章起只有简单的指引,适合爱好挑战和自学的读者。
可以购买有详细指导+背景知识的完整版。