本文次要介绍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.Leftast.Join.Rightast.Join.Tpast.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开始。