本文次要介绍 TinySQL 的 proj2 的具体思路以及实现形式
文件 tinysql/parser/parser.y:3806
JoinTable:
/* Use %prec to evaluate production TableRef before cross join */
TableRef CrossOpt TableRef %prec tableRefPriority
{$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin}
}
/* Your code here. */
在上述文件地位追加写入 JoinTable 的语法定义,测试不通过的 case 为
select * from t1 join t2 left join t3 on t2.id = t3.id
报错提醒为
FAIL: parser_test.go:300: testParserSuite.TestDMLStmt
parser_test.go:426:
s.RunTest(c, table)
parser_test.go:283:
c.Assert(err, IsNil, comment)
... value *errors.withStack = line 1 column 29 near "left join t3 on t2.id = t3.id" ("line 1 column 29 near \"left join t3 on t2.id = t3.id\" ")
... source select * from t1 join t2 left join t3 on t2.id = t3.id
能够看到谬误起始地位为 left join
局部,因而须要观测 Join 语句的定义地位,一个一个项拆解看看须要如何补充。原始定义为 TableRef CrossOpt TableRef %prec tableRefPriority
,拆解进去包含了TableRef
/ CrossOpt
/ %prec
/ tableRefPriority
这四项
其中 TableRef
的定义位于 tinysql/parser/parser.y:3674
TableRef:
TableFactor
{$$ = $1}
| JoinTable
{$$ = $1}
因而表援用要么就是 TableFactor
,要么就是JoinTable
。对于TableFactor
的定义,能够看 tinysql/parser/parser.y:3684,这里不在进一步开展,这个构造次要是对单表进行定义。联合 JoinTable
的定义能够看到这两个语法结构的定义是互相援用的。回到下面不通过的 case
t1 join t2 left join t3 on t2.id = t3.id
其中,t1 join t2
局部能够被曾经定义的 JoinTable
构造给正确解释,次要的问题在于依据以后的定义,没有方法解释前面的 left join t3 on t2.id = t3.id
这部分内容,包含了连接符和连贯条件。把 t1 join t2
看做是一个 TableRef
表援用,对这部分进行字面意义的拆解的话,这里能够解释为
TableRef $ 连贯类型 "JOIN" TableRef "ON" $ 连贯条件
那么,找到上下文中的对于连贯类型的定义,JoinType
JoinType:
"LEFT"
{$$ = ast.LeftJoin}
| "RIGHT"
{$$ = ast.RightJoin}
对于连贯条件,其实表现形式是和 Select 语句中的 WHERE t2.id = t3.id
相似的,而参考与 Select 解决相干的 WhereClause
的定义 tinysql/parser/parser.y:5290
WhereClause:
"WHERE" Expression
{$$ = $2}
能够看到,条件局部局部被定义为了表达式 Expression
,那么在JoinTable
外面也能够间接用表达式 Expression
来定义,因而拆解结束之后,须要补充的定义如下:
TableRef JoinType "JOIN" TableRef "ON" Expression
这样咱们就实现了对于 t1 join t2 left join t3 on t2.id = t3.id
的适配,那么接下来就是要确定如何解决这部分的语法,从 JoinTable
的原定义中,能够看到语法中的 JoinTable
对应的是 go 中的 ast.Join
构造,那么在 tinysql/parser/ast/dml.go:56 能够找到定义如下:
// Join represents table join.
type Join struct {
node
// Left table can be TableSource or JoinNode.
Left ResultSetNode
// Right table can be TableSource or JoinNode or nil.
Right ResultSetNode
// Tp represents join type.
Tp JoinType
// On represents join on condition.
On *OnCondition
}
这里咱们须要对 ast.Join.Left
、ast.Join.Right
、ast.Join.Tp
、ast.Join.On
进行赋值,参考原始定义中的写法进行定义如下:
JoinTable:
/* Use %prec to evaluate production TableRef before cross join */
TableRef CrossOpt TableRef %prec tableRefPriority
{$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin}
}
/* Your code here. */
| TableRef JoinType "JOIN" TableRef "ON" Expression %prec tableRefPriority
{
$$ = &ast.Join{Left: $1.(ast.ResultSetNode), // 这里取出第 1 个局部 TableRef 的值作为 Left
Right: $4.(ast.ResultSetNode), // 这里取出第 4 个局部 TableRef 的值作为 Right
Tp: $2.(ast.JoinType), // 这里取出第 2 局部的 JoinType 的值作为 Tp
On: &ast.OnCondition{Expr: $6.(ast.ExprNode)}, // 这里是咱们新增的局部,标识条件,即第 6 局部 Expression 的值
}
}
$$
示意本节点的值,$[n]
标识构造中第 n 的局部的值,从 1 开始。