本文次要介绍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.TestDMLStmtparser_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开始。